1 /*
2 ** io.c - IO class
3 */
4
5 #include "mruby.h"
6 #include "mruby/array.h"
7 #include "mruby/class.h"
8 #include "mruby/data.h"
9 #include "mruby/hash.h"
10 #include "mruby/string.h"
11 #include "mruby/variable.h"
12 #include "mruby/ext/io.h"
13
14 #if MRUBY_RELEASE_NO < 10000
15 #include "error.h"
16 #else
17 #include "mruby/error.h"
18 #endif
19
20 #include <sys/types.h>
21 #include <sys/stat.h>
22
23 #if defined(_WIN32) || defined(_WIN64)
24 #include <winsock.h>
25 #include <io.h>
26 #define open _open
27 #define close _close
28 #define dup _dup
29 #define dup2 _dup2
30 #define read _read
31 #define write _write
32 #define lseek _lseek
33 #define isatty _isatty
34 #define WEXITSTATUS(x) (x)
35 typedef int fsize_t;
36 typedef long ftime_t;
37 typedef long fsuseconds_t;
38 typedef int fmode_t;
39
40 #else
41 #include <sys/wait.h>
42 #include <unistd.h>
43 typedef size_t fsize_t;
44 typedef time_t ftime_t;
45 typedef suseconds_t fsuseconds_t;
46 typedef mode_t fmode_t;
47 #endif
48
49 #ifdef _MSC_VER
50 typedef mrb_int pid_t;
51 #endif
52
53 #include <fcntl.h>
54
55 #include <errno.h>
56 #include <stdio.h>
57 #include <string.h>
58
59
60 static void mrb_io_free(mrb_state *mrb, void *ptr);
61 struct mrb_data_type mrb_io_type = { "IO", mrb_io_free };
62
63
64 static struct mrb_io *io_get_open_fptr(mrb_state *mrb, mrb_value self);
65 static int mrb_io_modestr_to_flags(mrb_state *mrb, const char *modestr);
66 static int mrb_io_flags_to_modenum(mrb_state *mrb, int flags);
67 static void fptr_finalize(mrb_state *mrb, struct mrb_io *fptr, int quiet);
68
69 #if MRUBY_RELEASE_NO < 10000
70 static struct RClass *
mrb_module_get(mrb_state * mrb,const char * name)71 mrb_module_get(mrb_state *mrb, const char *name)
72 {
73 return mrb_class_get(mrb, name);
74 }
75 #endif
76
77 static struct mrb_io *
io_get_open_fptr(mrb_state * mrb,mrb_value self)78 io_get_open_fptr(mrb_state *mrb, mrb_value self)
79 {
80 struct mrb_io *fptr;
81
82 fptr = (struct mrb_io *)mrb_get_datatype(mrb, self, &mrb_io_type);
83 if (fptr == NULL) {
84 mrb_raise(mrb, E_IO_ERROR, "uninitialized stream.");
85 }
86 if (fptr->fd < 0) {
87 mrb_raise(mrb, E_IO_ERROR, "closed stream.");
88 }
89 return fptr;
90 }
91
92 static void
io_set_process_status(mrb_state * mrb,pid_t pid,int status)93 io_set_process_status(mrb_state *mrb, pid_t pid, int status)
94 {
95 struct RClass *c_process, *c_status;
96 mrb_value v;
97
98 c_status = NULL;
99 if (mrb_class_defined(mrb, "Process")) {
100 c_process = mrb_module_get(mrb, "Process");
101 if (mrb_const_defined(mrb, mrb_obj_value(c_process), mrb_intern_cstr(mrb, "Status"))) {
102 c_status = mrb_class_get_under(mrb, c_process, "Status");
103 }
104 }
105 if (c_status != NULL) {
106 v = mrb_funcall(mrb, mrb_obj_value(c_status), "new", 2, mrb_fixnum_value(pid), mrb_fixnum_value(status));
107 } else {
108 v = mrb_fixnum_value(WEXITSTATUS(status));
109 }
110 mrb_gv_set(mrb, mrb_intern_cstr(mrb, "$?"), v);
111 }
112
113 static int
mrb_io_modestr_to_flags(mrb_state * mrb,const char * mode)114 mrb_io_modestr_to_flags(mrb_state *mrb, const char *mode)
115 {
116 int flags = 0;
117 const char *m = mode;
118
119 switch (*m++) {
120 case 'r':
121 flags |= FMODE_READABLE;
122 break;
123 case 'w':
124 flags |= FMODE_WRITABLE | FMODE_CREATE | FMODE_TRUNC;
125 break;
126 case 'a':
127 flags |= FMODE_WRITABLE | FMODE_APPEND | FMODE_CREATE;
128 break;
129 default:
130 mrb_raisef(mrb, E_ARGUMENT_ERROR, "illegal access mode %S", mrb_str_new_cstr(mrb, mode));
131 }
132
133 while (*m) {
134 switch (*m++) {
135 case 'b':
136 flags |= FMODE_BINMODE;
137 break;
138 case '+':
139 flags |= FMODE_READWRITE;
140 break;
141 case ':':
142 /* XXX: PASSTHROUGH*/
143 default:
144 mrb_raisef(mrb, E_ARGUMENT_ERROR, "illegal access mode %S", mrb_str_new_cstr(mrb, mode));
145 }
146 }
147
148 return flags;
149 }
150
151 static int
mrb_io_flags_to_modenum(mrb_state * mrb,int flags)152 mrb_io_flags_to_modenum(mrb_state *mrb, int flags)
153 {
154 int modenum = 0;
155
156 switch(flags & (FMODE_READABLE|FMODE_WRITABLE|FMODE_READWRITE)) {
157 case FMODE_READABLE:
158 modenum = O_RDONLY;
159 break;
160 case FMODE_WRITABLE:
161 modenum = O_WRONLY;
162 break;
163 case FMODE_READWRITE:
164 modenum = O_RDWR;
165 break;
166 }
167
168 if (flags & FMODE_APPEND) {
169 modenum |= O_APPEND;
170 }
171 if (flags & FMODE_TRUNC) {
172 modenum |= O_TRUNC;
173 }
174 if (flags & FMODE_CREATE) {
175 modenum |= O_CREAT;
176 }
177 #ifdef O_BINARY
178 if (flags & FMODE_BINMODE) {
179 modenum |= O_BINARY;
180 }
181 #endif
182
183 return modenum;
184 }
185
186 static void
mrb_fd_cloexec(mrb_state * mrb,int fd)187 mrb_fd_cloexec(mrb_state *mrb, int fd)
188 {
189 #if defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
190 int flags, flags2;
191
192 flags = fcntl(fd, F_GETFD);
193 if (flags == -1) {
194 mrb_bug(mrb, "mrb_fd_cloexec: fcntl(%S, F_GETFD) failed: %S",
195 mrb_fixnum_value(fd), mrb_fixnum_value(errno));
196 }
197 if (fd <= 2) {
198 flags2 = flags & ~FD_CLOEXEC; /* Clear CLOEXEC for standard file descriptors: 0, 1, 2. */
199 }
200 else {
201 flags2 = flags | FD_CLOEXEC; /* Set CLOEXEC for non-standard file descriptors: 3, 4, 5, ... */
202 }
203 if (flags != flags2) {
204 if (fcntl(fd, F_SETFD, flags2) == -1) {
205 mrb_bug(mrb, "mrb_fd_cloexec: fcntl(%S, F_SETFD, %S) failed: %S",
206 mrb_fixnum_value(fd), mrb_fixnum_value(flags2), mrb_fixnum_value(errno));
207 }
208 }
209 #endif
210 }
211
212 #if !defined(_WIN32) && !(defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE)
213 static int
mrb_cloexec_pipe(mrb_state * mrb,int fildes[2])214 mrb_cloexec_pipe(mrb_state *mrb, int fildes[2])
215 {
216 int ret;
217 ret = pipe(fildes);
218 if (ret == -1)
219 return -1;
220 mrb_fd_cloexec(mrb, fildes[0]);
221 mrb_fd_cloexec(mrb, fildes[1]);
222 return ret;
223 }
224
225 static int
mrb_pipe(mrb_state * mrb,int pipes[2])226 mrb_pipe(mrb_state *mrb, int pipes[2])
227 {
228 int ret;
229 ret = mrb_cloexec_pipe(mrb, pipes);
230 if (ret == -1) {
231 if (errno == EMFILE || errno == ENFILE) {
232 mrb_garbage_collect(mrb);
233 ret = mrb_cloexec_pipe(mrb, pipes);
234 }
235 }
236 return ret;
237 }
238
239 static int
mrb_proc_exec(const char * pname)240 mrb_proc_exec(const char *pname)
241 {
242 const char *s;
243 s = pname;
244
245 while (*s == ' ' || *s == '\t' || *s == '\n')
246 s++;
247
248 if (!*s) {
249 errno = ENOENT;
250 return -1;
251 }
252
253 execl("/bin/sh", "sh", "-c", pname, (char *)NULL);
254 return -1;
255 }
256 #endif
257
258 static void
mrb_io_free(mrb_state * mrb,void * ptr)259 mrb_io_free(mrb_state *mrb, void *ptr)
260 {
261 struct mrb_io *io = (struct mrb_io *)ptr;
262 if (io != NULL) {
263 fptr_finalize(mrb, io, TRUE);
264 mrb_free(mrb, io);
265 }
266 }
267
268 static struct mrb_io *
mrb_io_alloc(mrb_state * mrb)269 mrb_io_alloc(mrb_state *mrb)
270 {
271 struct mrb_io *fptr;
272
273 fptr = (struct mrb_io *)mrb_malloc(mrb, sizeof(struct mrb_io));
274 fptr->fd = -1;
275 fptr->fd2 = -1;
276 fptr->pid = 0;
277 fptr->readable = 0;
278 fptr->writable = 0;
279 fptr->sync = 0;
280 fptr->is_socket = 0;
281 return fptr;
282 }
283
284 #ifndef NOFILE
285 #define NOFILE 64
286 #endif
287
288 static int
option_to_fd(mrb_state * mrb,mrb_value obj,const char * key)289 option_to_fd(mrb_state *mrb, mrb_value obj, const char *key)
290 {
291 mrb_value opt = mrb_funcall(mrb, obj, "[]", 1, mrb_symbol_value(mrb_intern_static(mrb, key, strlen(key))));
292 if (mrb_nil_p(opt)) {
293 return -1;
294 }
295
296 switch (mrb_type(opt)) {
297 case MRB_TT_DATA: /* IO */
298 return (int)mrb_fixnum(mrb_io_fileno(mrb, opt));
299 case MRB_TT_FIXNUM:
300 return (int)mrb_fixnum(opt);
301 default:
302 mrb_raise(mrb, E_ARGUMENT_ERROR, "wrong exec redirect action");
303 break;
304 }
305 return -1; /* never reached */
306 }
307
308 #ifdef _WIN32
309 mrb_value
mrb_io_s_popen(mrb_state * mrb,mrb_value klass)310 mrb_io_s_popen(mrb_state *mrb, mrb_value klass)
311 {
312 mrb_value cmd, io;
313 mrb_value mode = mrb_str_new_cstr(mrb, "r");
314 mrb_value opt = mrb_hash_new(mrb);
315
316 struct mrb_io *fptr;
317 const char *pname;
318 int pid = 0, flags;
319 STARTUPINFO si;
320 PROCESS_INFORMATION pi;
321 SECURITY_ATTRIBUTES saAttr;
322
323 HANDLE ifd[2];
324 HANDLE ofd[2];
325
326 int doexec;
327 int opt_in, opt_out, opt_err;
328
329 ifd[0] = INVALID_HANDLE_VALUE;
330 ifd[1] = INVALID_HANDLE_VALUE;
331 ofd[0] = INVALID_HANDLE_VALUE;
332 ofd[1] = INVALID_HANDLE_VALUE;
333
334 mrb_get_args(mrb, "S|SH", &cmd, &mode, &opt);
335 io = mrb_obj_value(mrb_data_object_alloc(mrb, mrb_class_ptr(klass), NULL, &mrb_io_type));
336
337 pname = mrb_string_value_cstr(mrb, &cmd);
338 flags = mrb_io_modestr_to_flags(mrb, mrb_string_value_cstr(mrb, &mode));
339
340 doexec = (strcmp("-", pname) != 0);
341 opt_in = option_to_fd(mrb, opt, "in");
342 opt_out = option_to_fd(mrb, opt, "out");
343 opt_err = option_to_fd(mrb, opt, "err");
344
345 saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
346 saAttr.bInheritHandle = TRUE;
347 saAttr.lpSecurityDescriptor = NULL;
348
349 if (flags & FMODE_READABLE) {
350 if (!CreatePipe(&ofd[0], &ofd[1], &saAttr, 0)
351 || !SetHandleInformation(ofd[0], HANDLE_FLAG_INHERIT, 0)) {
352 mrb_sys_fail(mrb, "pipe");
353 }
354 }
355
356 if (flags & FMODE_WRITABLE) {
357 if (!CreatePipe(&ifd[0], &ifd[1], &saAttr, 0)
358 || !SetHandleInformation(ifd[1], HANDLE_FLAG_INHERIT, 0)) {
359 mrb_sys_fail(mrb, "pipe");
360 }
361 }
362
363 if (doexec) {
364 ZeroMemory(&pi, sizeof(pi));
365 ZeroMemory(&si, sizeof(si));
366 si.cb = sizeof(si);
367 si.dwFlags |= STARTF_USESHOWWINDOW;
368 si.wShowWindow = SW_HIDE;
369 si.dwFlags |= STARTF_USESTDHANDLES;
370 if (flags & FMODE_READABLE) {
371 si.hStdOutput = ofd[1];
372 si.hStdError = ofd[1];
373 }
374 if (flags & FMODE_WRITABLE) {
375 si.hStdInput = ifd[0];
376 }
377 if (!CreateProcess(
378 NULL, (char*)pname, NULL, NULL,
379 TRUE, CREATE_NEW_PROCESS_GROUP, NULL, NULL, &si, &pi)) {
380 CloseHandle(ifd[0]);
381 CloseHandle(ifd[1]);
382 CloseHandle(ofd[0]);
383 CloseHandle(ofd[1]);
384 mrb_raisef(mrb, E_IO_ERROR, "command not found: %S", cmd);
385 }
386 CloseHandle(pi.hThread);
387 CloseHandle(ifd[0]);
388 CloseHandle(ofd[1]);
389 pid = pi.dwProcessId;
390 }
391
392 mrb_iv_set(mrb, io, mrb_intern_cstr(mrb, "@buf"), mrb_str_new_cstr(mrb, ""));
393
394 fptr = mrb_io_alloc(mrb);
395 fptr->fd = _open_osfhandle((intptr_t)ofd[0], 0);
396 fptr->fd2 = _open_osfhandle((intptr_t)ifd[1], 0);
397 fptr->pid = pid;
398 fptr->readable = ((flags & FMODE_READABLE) != 0);
399 fptr->writable = ((flags & FMODE_WRITABLE) != 0);
400 fptr->sync = 0;
401
402 DATA_TYPE(io) = &mrb_io_type;
403 DATA_PTR(io) = fptr;
404 return io;
405 }
406 #elif defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE
407 mrb_value
mrb_io_s_popen(mrb_state * mrb,mrb_value klass)408 mrb_io_s_popen(mrb_state *mrb, mrb_value klass)
409 {
410 mrb_raise(mrb, E_NOTIMP_ERROR, "IO#popen is not supported on the platform");
411 return mrb_false_value();
412 }
413 #else
414 mrb_value
mrb_io_s_popen(mrb_state * mrb,mrb_value klass)415 mrb_io_s_popen(mrb_state *mrb, mrb_value klass)
416 {
417 mrb_value cmd, io, result;
418 mrb_value mode = mrb_str_new_cstr(mrb, "r");
419 mrb_value opt = mrb_hash_new(mrb);
420
421 struct mrb_io *fptr;
422 const char *pname;
423 int pid, flags, fd, write_fd = -1;
424 int pr[2] = { -1, -1 };
425 int pw[2] = { -1, -1 };
426 int doexec;
427 int saved_errno;
428 int opt_in, opt_out, opt_err;
429
430 mrb_get_args(mrb, "S|SH", &cmd, &mode, &opt);
431 io = mrb_obj_value(mrb_data_object_alloc(mrb, mrb_class_ptr(klass), NULL, &mrb_io_type));
432
433 pname = mrb_string_value_cstr(mrb, &cmd);
434 flags = mrb_io_modestr_to_flags(mrb, mrb_string_value_cstr(mrb, &mode));
435
436 doexec = (strcmp("-", pname) != 0);
437 opt_in = option_to_fd(mrb, opt, "in");
438 opt_out = option_to_fd(mrb, opt, "out");
439 opt_err = option_to_fd(mrb, opt, "err");
440
441 if (flags & FMODE_READABLE) {
442 if (pipe(pr) == -1) {
443 mrb_sys_fail(mrb, "pipe");
444 }
445 mrb_fd_cloexec(mrb, pr[0]);
446 mrb_fd_cloexec(mrb, pr[1]);
447 }
448
449 if (flags & FMODE_WRITABLE) {
450 if (pipe(pw) == -1) {
451 if (pr[0] != -1) close(pr[0]);
452 if (pr[1] != -1) close(pr[1]);
453 mrb_sys_fail(mrb, "pipe");
454 }
455 mrb_fd_cloexec(mrb, pw[0]);
456 mrb_fd_cloexec(mrb, pw[1]);
457 }
458
459 if (!doexec) {
460 // XXX
461 fflush(stdin);
462 fflush(stdout);
463 fflush(stderr);
464 }
465
466 result = mrb_nil_value();
467 switch (pid = fork()) {
468 case 0: /* child */
469 if (opt_in != -1) {
470 dup2(opt_in, 0);
471 }
472 if (opt_out != -1) {
473 dup2(opt_out, 1);
474 }
475 if (opt_err != -1) {
476 dup2(opt_err, 2);
477 }
478 if (flags & FMODE_READABLE) {
479 close(pr[0]);
480 if (pr[1] != 1) {
481 dup2(pr[1], 1);
482 close(pr[1]);
483 }
484 }
485 if (flags & FMODE_WRITABLE) {
486 close(pw[1]);
487 if (pw[0] != 0) {
488 dup2(pw[0], 0);
489 close(pw[0]);
490 }
491 }
492 if (doexec) {
493 for (fd = 3; fd < NOFILE; fd++) {
494 close(fd);
495 }
496 mrb_proc_exec(pname);
497 mrb_raisef(mrb, E_IO_ERROR, "command not found: %S", cmd);
498 _exit(127);
499 }
500 result = mrb_nil_value();
501 break;
502
503 default: /* parent */
504 if ((flags & FMODE_READABLE) && (flags & FMODE_WRITABLE)) {
505 close(pr[1]);
506 fd = pr[0];
507 close(pw[0]);
508 write_fd = pw[1];
509 } else if (flags & FMODE_READABLE) {
510 close(pr[1]);
511 fd = pr[0];
512 } else {
513 close(pw[0]);
514 fd = pw[1];
515 }
516
517 mrb_iv_set(mrb, io, mrb_intern_cstr(mrb, "@buf"), mrb_str_new_cstr(mrb, ""));
518
519 fptr = mrb_io_alloc(mrb);
520 fptr->fd = fd;
521 fptr->fd2 = write_fd;
522 fptr->pid = pid;
523 fptr->readable = ((flags & FMODE_READABLE) != 0);
524 fptr->writable = ((flags & FMODE_WRITABLE) != 0);
525 fptr->sync = 0;
526
527 DATA_TYPE(io) = &mrb_io_type;
528 DATA_PTR(io) = fptr;
529 result = io;
530 break;
531
532 case -1: /* error */
533 saved_errno = errno;
534 if (flags & FMODE_READABLE) {
535 close(pr[0]);
536 close(pr[1]);
537 }
538 if (flags & FMODE_WRITABLE) {
539 close(pw[0]);
540 close(pw[1]);
541 }
542 errno = saved_errno;
543 mrb_sys_fail(mrb, "pipe_open failed.");
544 break;
545 }
546 return result;
547 }
548 #endif
549
550 static int
mrb_dup(mrb_state * mrb,int fd,mrb_bool * failed)551 mrb_dup(mrb_state *mrb, int fd, mrb_bool *failed)
552 {
553 int new_fd;
554
555 *failed = TRUE;
556 if (fd < 0)
557 return fd;
558
559 new_fd = dup(fd);
560 if (new_fd > 0) *failed = FALSE;
561 return new_fd;
562 }
563
564 mrb_value
mrb_io_initialize_copy(mrb_state * mrb,mrb_value copy)565 mrb_io_initialize_copy(mrb_state *mrb, mrb_value copy)
566 {
567 mrb_value orig;
568 mrb_value buf;
569 struct mrb_io *fptr_copy;
570 struct mrb_io *fptr_orig;
571 mrb_bool failed = TRUE;
572
573 mrb_get_args(mrb, "o", &orig);
574 fptr_orig = io_get_open_fptr(mrb, orig);
575 fptr_copy = (struct mrb_io *)DATA_PTR(copy);
576 if (fptr_orig == fptr_copy) return copy;
577 if (fptr_copy != NULL) {
578 fptr_finalize(mrb, fptr_copy, FALSE);
579 mrb_free(mrb, fptr_copy);
580 }
581 fptr_copy = (struct mrb_io *)mrb_io_alloc(mrb);
582
583 DATA_TYPE(copy) = &mrb_io_type;
584 DATA_PTR(copy) = fptr_copy;
585
586 buf = mrb_iv_get(mrb, orig, mrb_intern_cstr(mrb, "@buf"));
587 mrb_iv_set(mrb, copy, mrb_intern_cstr(mrb, "@buf"), buf);
588
589 fptr_copy->fd = mrb_dup(mrb, fptr_orig->fd, &failed);
590 if (failed) {
591 mrb_sys_fail(mrb, 0);
592 }
593 mrb_fd_cloexec(mrb, fptr_copy->fd);
594
595 if (fptr_orig->fd2 != -1) {
596 fptr_copy->fd2 = mrb_dup(mrb, fptr_orig->fd2, &failed);
597 if (failed) {
598 close(fptr_copy->fd);
599 mrb_sys_fail(mrb, 0);
600 }
601 mrb_fd_cloexec(mrb, fptr_copy->fd2);
602 }
603
604 fptr_copy->pid = fptr_orig->pid;
605 fptr_copy->readable = fptr_orig->readable;
606 fptr_copy->writable = fptr_orig->writable;
607 fptr_copy->sync = fptr_orig->sync;
608 fptr_copy->is_socket = fptr_orig->is_socket;
609
610 return copy;
611 }
612
613 mrb_value
mrb_io_initialize(mrb_state * mrb,mrb_value io)614 mrb_io_initialize(mrb_state *mrb, mrb_value io)
615 {
616 struct mrb_io *fptr;
617 mrb_int fd;
618 mrb_value mode, opt;
619 int flags;
620
621 mode = opt = mrb_nil_value();
622
623 mrb_get_args(mrb, "i|So", &fd, &mode, &opt);
624 if (mrb_nil_p(mode)) {
625 mode = mrb_str_new_cstr(mrb, "r");
626 }
627 if (mrb_nil_p(opt)) {
628 opt = mrb_hash_new(mrb);
629 }
630
631 flags = mrb_io_modestr_to_flags(mrb, mrb_string_value_cstr(mrb, &mode));
632
633 mrb_iv_set(mrb, io, mrb_intern_cstr(mrb, "@buf"), mrb_str_new_cstr(mrb, ""));
634
635 fptr = (struct mrb_io *)DATA_PTR(io);
636 if (fptr != NULL) {
637 fptr_finalize(mrb, fptr, TRUE);
638 mrb_free(mrb, fptr);
639 }
640 fptr = mrb_io_alloc(mrb);
641
642 DATA_TYPE(io) = &mrb_io_type;
643 DATA_PTR(io) = fptr;
644
645 fptr->fd = (int)fd;
646 fptr->readable = ((flags & FMODE_READABLE) != 0);
647 fptr->writable = ((flags & FMODE_WRITABLE) != 0);
648 fptr->sync = 0;
649 return io;
650 }
651
652 static void
fptr_finalize(mrb_state * mrb,struct mrb_io * fptr,int quiet)653 fptr_finalize(mrb_state *mrb, struct mrb_io *fptr, int quiet)
654 {
655 int saved_errno = 0;
656
657 if (fptr == NULL) {
658 return;
659 }
660
661 if (fptr->fd > 2) {
662 #ifdef _WIN32
663 if (fptr->is_socket) {
664 if (closesocket(fptr->fd) != 0) {
665 saved_errno = WSAGetLastError();
666 }
667 fptr->fd = -1;
668 }
669 #endif
670 if (fptr->fd != -1) {
671 if (close(fptr->fd) == -1) {
672 saved_errno = errno;
673 }
674 }
675 fptr->fd = -1;
676 }
677
678 if (fptr->fd2 > 2) {
679 if (close(fptr->fd2) == -1) {
680 if (saved_errno == 0) {
681 saved_errno = errno;
682 }
683 }
684 fptr->fd2 = -1;
685 }
686
687 if (fptr->pid != 0) {
688 #if !defined(_WIN32) && !defined(_WIN64)
689 pid_t pid;
690 int status;
691 do {
692 pid = waitpid(fptr->pid, &status, 0);
693 } while (pid == -1 && errno == EINTR);
694 if (!quiet && pid == fptr->pid) {
695 io_set_process_status(mrb, pid, status);
696 }
697 #else
698 HANDLE h = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, fptr->pid);
699 DWORD status;
700 if (WaitForSingleObject(h, INFINITE) && GetExitCodeProcess(h, &status))
701 if (!quiet)
702 io_set_process_status(mrb, fptr->pid, (int)status);
703 CloseHandle(h);
704 #endif
705 fptr->pid = 0;
706 /* Note: we don't raise an exception when waitpid(3) fails */
707 }
708
709 if (!quiet && saved_errno != 0) {
710 errno = saved_errno;
711 mrb_sys_fail(mrb, "fptr_finalize failed.");
712 }
713 }
714
715 mrb_value
mrb_io_check_readable(mrb_state * mrb,mrb_value self)716 mrb_io_check_readable(mrb_state *mrb, mrb_value self)
717 {
718 struct mrb_io *fptr = io_get_open_fptr(mrb, self);
719 if (! fptr->readable) {
720 mrb_raise(mrb, E_IO_ERROR, "not opened for reading");
721 }
722 return mrb_nil_value();
723 }
724
725 mrb_value
mrb_io_isatty(mrb_state * mrb,mrb_value self)726 mrb_io_isatty(mrb_state *mrb, mrb_value self)
727 {
728 struct mrb_io *fptr;
729
730 fptr = io_get_open_fptr(mrb, self);
731 if (isatty(fptr->fd) == 0)
732 return mrb_false_value();
733 return mrb_true_value();
734 }
735
736 mrb_value
mrb_io_s_for_fd(mrb_state * mrb,mrb_value klass)737 mrb_io_s_for_fd(mrb_state *mrb, mrb_value klass)
738 {
739 struct RClass *c = mrb_class_ptr(klass);
740 enum mrb_vtype ttype = MRB_INSTANCE_TT(c);
741 mrb_value obj;
742
743 /* copied from mrb_instance_alloc() */
744 if (ttype == 0) ttype = MRB_TT_OBJECT;
745 obj = mrb_obj_value((struct RObject*)mrb_obj_alloc(mrb, ttype, c));
746 return mrb_io_initialize(mrb, obj);
747 }
748
749 mrb_value
mrb_io_s_sysclose(mrb_state * mrb,mrb_value klass)750 mrb_io_s_sysclose(mrb_state *mrb, mrb_value klass)
751 {
752 mrb_int fd;
753 mrb_get_args(mrb, "i", &fd);
754 if (close((int)fd) == -1) {
755 mrb_sys_fail(mrb, "close");
756 }
757 return mrb_fixnum_value(0);
758 }
759
760 int
mrb_cloexec_open(mrb_state * mrb,const char * pathname,mrb_int flags,mrb_int mode)761 mrb_cloexec_open(mrb_state *mrb, const char *pathname, mrb_int flags, mrb_int mode)
762 {
763 mrb_value emsg;
764 int fd, retry = FALSE;
765 char* fname = mrb_locale_from_utf8(pathname, -1);
766
767 #ifdef O_CLOEXEC
768 /* O_CLOEXEC is available since Linux 2.6.23. Linux 2.6.18 silently ignore it. */
769 flags |= O_CLOEXEC;
770 #elif defined O_NOINHERIT
771 flags |= O_NOINHERIT;
772 #endif
773 reopen:
774 fd = open(fname, (int)flags, (fmode_t)mode);
775 if (fd == -1) {
776 if (!retry) {
777 switch (errno) {
778 case ENFILE:
779 case EMFILE:
780 mrb_garbage_collect(mrb);
781 retry = TRUE;
782 goto reopen;
783 }
784 }
785
786 emsg = mrb_format(mrb, "open %S", mrb_str_new_cstr(mrb, pathname));
787 mrb_str_modify(mrb, mrb_str_ptr(emsg));
788 mrb_sys_fail(mrb, RSTRING_PTR(emsg));
789 }
790 mrb_locale_free(fname);
791
792 if (fd <= 2) {
793 mrb_fd_cloexec(mrb, fd);
794 }
795 return fd;
796 }
797
798 mrb_value
mrb_io_s_sysopen(mrb_state * mrb,mrb_value klass)799 mrb_io_s_sysopen(mrb_state *mrb, mrb_value klass)
800 {
801 mrb_value path = mrb_nil_value();
802 mrb_value mode = mrb_nil_value();
803 mrb_int fd, perm = -1;
804 const char *pat;
805 int flags, modenum;
806
807 mrb_get_args(mrb, "S|Si", &path, &mode, &perm);
808 if (mrb_nil_p(mode)) {
809 mode = mrb_str_new_cstr(mrb, "r");
810 }
811 if (perm < 0) {
812 perm = 0666;
813 }
814
815 pat = mrb_string_value_cstr(mrb, &path);
816 flags = mrb_io_modestr_to_flags(mrb, mrb_string_value_cstr(mrb, &mode));
817 modenum = mrb_io_flags_to_modenum(mrb, flags);
818 fd = mrb_cloexec_open(mrb, pat, modenum, perm);
819 return mrb_fixnum_value(fd);
820 }
821
822 mrb_value
mrb_io_sysread(mrb_state * mrb,mrb_value io)823 mrb_io_sysread(mrb_state *mrb, mrb_value io)
824 {
825 struct mrb_io *fptr;
826 mrb_value buf = mrb_nil_value();
827 mrb_int maxlen;
828 int ret;
829
830 mrb_get_args(mrb, "i|S", &maxlen, &buf);
831 if (maxlen < 0) {
832 mrb_raise(mrb, E_ARGUMENT_ERROR, "negative expanding string size");
833 }
834 else if (maxlen == 0) {
835 return mrb_str_new(mrb, NULL, maxlen);
836 }
837
838 if (mrb_nil_p(buf)) {
839 buf = mrb_str_new(mrb, NULL, maxlen);
840 }
841
842 if (RSTRING_LEN(buf) != maxlen) {
843 buf = mrb_str_resize(mrb, buf, maxlen);
844 } else {
845 mrb_str_modify(mrb, RSTRING(buf));
846 }
847
848 fptr = (struct mrb_io *)io_get_open_fptr(mrb, io);
849 if (!fptr->readable) {
850 mrb_raise(mrb, E_IO_ERROR, "not opened for reading");
851 }
852 ret = read(fptr->fd, RSTRING_PTR(buf), (fsize_t)maxlen);
853 switch (ret) {
854 case 0: /* EOF */
855 if (maxlen == 0) {
856 buf = mrb_str_new_cstr(mrb, "");
857 } else {
858 mrb_raise(mrb, E_EOF_ERROR, "sysread failed: End of File");
859 }
860 break;
861 case -1: /* Error */
862 mrb_sys_fail(mrb, "sysread failed");
863 break;
864 default:
865 if (RSTRING_LEN(buf) != ret) {
866 buf = mrb_str_resize(mrb, buf, ret);
867 }
868 break;
869 }
870
871 return buf;
872 }
873
874 mrb_value
mrb_io_sysseek(mrb_state * mrb,mrb_value io)875 mrb_io_sysseek(mrb_state *mrb, mrb_value io)
876 {
877 struct mrb_io *fptr;
878 off_t pos;
879 mrb_int offset, whence = -1;
880
881 mrb_get_args(mrb, "i|i", &offset, &whence);
882 if (whence < 0) {
883 whence = 0;
884 }
885
886 fptr = io_get_open_fptr(mrb, io);
887 pos = lseek(fptr->fd, (off_t)offset, (int)whence);
888 if (pos == -1) {
889 mrb_sys_fail(mrb, "sysseek");
890 }
891 if (pos > MRB_INT_MAX) {
892 #ifndef MRB_WITHOUT_FLOAT
893 return mrb_float_value(mrb, (mrb_float)pos);
894 #else
895 mrb_raise(mrb, E_IO_ERROR, "sysseek reached too far for MRB_WITHOUT_FLOAT");
896 #endif
897 } else {
898 return mrb_fixnum_value(pos);
899 }
900 }
901
902 mrb_value
mrb_io_syswrite(mrb_state * mrb,mrb_value io)903 mrb_io_syswrite(mrb_state *mrb, mrb_value io)
904 {
905 struct mrb_io *fptr;
906 mrb_value str, buf;
907 int fd, length;
908
909 fptr = io_get_open_fptr(mrb, io);
910 if (! fptr->writable) {
911 mrb_raise(mrb, E_IO_ERROR, "not opened for writing");
912 }
913
914 mrb_get_args(mrb, "S", &str);
915 if (mrb_type(str) != MRB_TT_STRING) {
916 buf = mrb_funcall(mrb, str, "to_s", 0);
917 } else {
918 buf = str;
919 }
920
921 if (fptr->fd2 == -1) {
922 fd = fptr->fd;
923 } else {
924 fd = fptr->fd2;
925 }
926 length = write(fd, RSTRING_PTR(buf), (fsize_t)RSTRING_LEN(buf));
927 if (length == -1) {
928 mrb_sys_fail(mrb, 0);
929 }
930
931 return mrb_fixnum_value(length);
932 }
933
934 mrb_value
mrb_io_close(mrb_state * mrb,mrb_value self)935 mrb_io_close(mrb_state *mrb, mrb_value self)
936 {
937 struct mrb_io *fptr;
938 fptr = io_get_open_fptr(mrb, self);
939 fptr_finalize(mrb, fptr, FALSE);
940 return mrb_nil_value();
941 }
942
943 mrb_value
mrb_io_close_write(mrb_state * mrb,mrb_value self)944 mrb_io_close_write(mrb_state *mrb, mrb_value self)
945 {
946 struct mrb_io *fptr;
947 fptr = io_get_open_fptr(mrb, self);
948 if (close((int)fptr->fd2) == -1) {
949 mrb_sys_fail(mrb, "close");
950 }
951 return mrb_nil_value();
952 }
953
954 mrb_value
mrb_io_closed(mrb_state * mrb,mrb_value io)955 mrb_io_closed(mrb_state *mrb, mrb_value io)
956 {
957 struct mrb_io *fptr;
958 fptr = (struct mrb_io *)mrb_get_datatype(mrb, io, &mrb_io_type);
959 if (fptr == NULL || fptr->fd >= 0) {
960 return mrb_false_value();
961 }
962
963 return mrb_true_value();
964 }
965
966 mrb_value
mrb_io_pid(mrb_state * mrb,mrb_value io)967 mrb_io_pid(mrb_state *mrb, mrb_value io)
968 {
969 struct mrb_io *fptr;
970 fptr = io_get_open_fptr(mrb, io);
971
972 if (fptr->pid > 0) {
973 return mrb_fixnum_value(fptr->pid);
974 }
975
976 return mrb_nil_value();
977 }
978
979 static struct timeval
time2timeval(mrb_state * mrb,mrb_value time)980 time2timeval(mrb_state *mrb, mrb_value time)
981 {
982 struct timeval t = { 0, 0 };
983
984 switch (mrb_type(time)) {
985 case MRB_TT_FIXNUM:
986 t.tv_sec = (ftime_t)mrb_fixnum(time);
987 t.tv_usec = 0;
988 break;
989
990 #ifndef MRB_WITHOUT_FLOAT
991 case MRB_TT_FLOAT:
992 t.tv_sec = (ftime_t)mrb_float(time);
993 t.tv_usec = (fsuseconds_t)((mrb_float(time) - t.tv_sec) * 1000000.0);
994 break;
995 #endif
996
997 default:
998 mrb_raise(mrb, E_TYPE_ERROR, "wrong argument class");
999 }
1000
1001 return t;
1002 }
1003
1004 static int
mrb_io_read_data_pending(mrb_state * mrb,mrb_value io)1005 mrb_io_read_data_pending(mrb_state *mrb, mrb_value io)
1006 {
1007 mrb_value buf = mrb_iv_get(mrb, io, mrb_intern_cstr(mrb, "@buf"));
1008 if (mrb_type(buf) == MRB_TT_STRING && RSTRING_LEN(buf) > 0) {
1009 return 1;
1010 }
1011 return 0;
1012 }
1013
1014 #if !defined(_WIN32) && !(defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE)
1015 static mrb_value
mrb_io_s_pipe(mrb_state * mrb,mrb_value klass)1016 mrb_io_s_pipe(mrb_state *mrb, mrb_value klass)
1017 {
1018 mrb_value r = mrb_nil_value();
1019 mrb_value w = mrb_nil_value();
1020 struct mrb_io *fptr_r;
1021 struct mrb_io *fptr_w;
1022 int pipes[2];
1023
1024 if (mrb_pipe(mrb, pipes) == -1) {
1025 mrb_sys_fail(mrb, "pipe");
1026 }
1027
1028 r = mrb_obj_value(mrb_data_object_alloc(mrb, mrb_class_ptr(klass), NULL, &mrb_io_type));
1029 mrb_iv_set(mrb, r, mrb_intern_cstr(mrb, "@buf"), mrb_str_new_cstr(mrb, ""));
1030 fptr_r = mrb_io_alloc(mrb);
1031 fptr_r->fd = pipes[0];
1032 fptr_r->readable = 1;
1033 fptr_r->writable = 0;
1034 fptr_r->sync = 0;
1035 DATA_TYPE(r) = &mrb_io_type;
1036 DATA_PTR(r) = fptr_r;
1037
1038 w = mrb_obj_value(mrb_data_object_alloc(mrb, mrb_class_ptr(klass), NULL, &mrb_io_type));
1039 mrb_iv_set(mrb, w, mrb_intern_cstr(mrb, "@buf"), mrb_str_new_cstr(mrb, ""));
1040 fptr_w = mrb_io_alloc(mrb);
1041 fptr_w->fd = pipes[1];
1042 fptr_w->readable = 0;
1043 fptr_w->writable = 1;
1044 fptr_w->sync = 1;
1045 DATA_TYPE(w) = &mrb_io_type;
1046 DATA_PTR(w) = fptr_w;
1047
1048 return mrb_assoc_new(mrb, r, w);
1049 }
1050 #endif
1051
1052 static mrb_value
mrb_io_s_select(mrb_state * mrb,mrb_value klass)1053 mrb_io_s_select(mrb_state *mrb, mrb_value klass)
1054 {
1055 mrb_value *argv;
1056 mrb_int argc;
1057 mrb_value read, read_io, write, except, timeout, list;
1058 struct timeval *tp, timerec;
1059 fd_set pset, rset, wset, eset;
1060 fd_set *rp, *wp, *ep;
1061 struct mrb_io *fptr;
1062 int pending = 0;
1063 mrb_value result;
1064 int max = 0;
1065 int interrupt_flag = 0;
1066 int i, n;
1067
1068 mrb_get_args(mrb, "*", &argv, &argc);
1069
1070 if (argc < 1 || argc > 4) {
1071 mrb_raisef(mrb, E_ARGUMENT_ERROR, "wrong number of arguments (%S for 1..4)", mrb_fixnum_value(argc));
1072 }
1073
1074 timeout = mrb_nil_value();
1075 except = mrb_nil_value();
1076 write = mrb_nil_value();
1077 if (argc > 3)
1078 timeout = argv[3];
1079 if (argc > 2)
1080 except = argv[2];
1081 if (argc > 1)
1082 write = argv[1];
1083 read = argv[0];
1084
1085 if (mrb_nil_p(timeout)) {
1086 tp = NULL;
1087 } else {
1088 timerec = time2timeval(mrb, timeout);
1089 tp = &timerec;
1090 }
1091
1092 FD_ZERO(&pset);
1093 if (!mrb_nil_p(read)) {
1094 mrb_check_type(mrb, read, MRB_TT_ARRAY);
1095 rp = &rset;
1096 FD_ZERO(rp);
1097 for (i = 0; i < RARRAY_LEN(read); i++) {
1098 read_io = RARRAY_PTR(read)[i];
1099 fptr = io_get_open_fptr(mrb, read_io);
1100 FD_SET(fptr->fd, rp);
1101 if (mrb_io_read_data_pending(mrb, read_io)) {
1102 pending++;
1103 FD_SET(fptr->fd, &pset);
1104 }
1105 if (max < fptr->fd)
1106 max = fptr->fd;
1107 }
1108 if (pending) {
1109 timerec.tv_sec = timerec.tv_usec = 0;
1110 tp = &timerec;
1111 }
1112 } else {
1113 rp = NULL;
1114 }
1115
1116 if (!mrb_nil_p(write)) {
1117 mrb_check_type(mrb, write, MRB_TT_ARRAY);
1118 wp = &wset;
1119 FD_ZERO(wp);
1120 for (i = 0; i < RARRAY_LEN(write); i++) {
1121 fptr = io_get_open_fptr(mrb, RARRAY_PTR(write)[i]);
1122 FD_SET(fptr->fd, wp);
1123 if (max < fptr->fd)
1124 max = fptr->fd;
1125 if (fptr->fd2 >= 0) {
1126 FD_SET(fptr->fd2, wp);
1127 if (max < fptr->fd2)
1128 max = fptr->fd2;
1129 }
1130 }
1131 } else {
1132 wp = NULL;
1133 }
1134
1135 if (!mrb_nil_p(except)) {
1136 mrb_check_type(mrb, except, MRB_TT_ARRAY);
1137 ep = &eset;
1138 FD_ZERO(ep);
1139 for (i = 0; i < RARRAY_LEN(except); i++) {
1140 fptr = io_get_open_fptr(mrb, RARRAY_PTR(except)[i]);
1141 FD_SET(fptr->fd, ep);
1142 if (max < fptr->fd)
1143 max = fptr->fd;
1144 if (fptr->fd2 >= 0) {
1145 FD_SET(fptr->fd2, ep);
1146 if (max < fptr->fd2)
1147 max = fptr->fd2;
1148 }
1149 }
1150 } else {
1151 ep = NULL;
1152 }
1153
1154 max++;
1155
1156 retry:
1157 n = select(max, rp, wp, ep, tp);
1158 if (n < 0) {
1159 if (errno != EINTR)
1160 mrb_sys_fail(mrb, "select failed");
1161 if (tp == NULL)
1162 goto retry;
1163 interrupt_flag = 1;
1164 }
1165
1166 if (!pending && n == 0)
1167 return mrb_nil_value();
1168
1169 result = mrb_ary_new_capa(mrb, 3);
1170 mrb_ary_push(mrb, result, rp? mrb_ary_new(mrb) : mrb_ary_new_capa(mrb, 0));
1171 mrb_ary_push(mrb, result, wp? mrb_ary_new(mrb) : mrb_ary_new_capa(mrb, 0));
1172 mrb_ary_push(mrb, result, ep? mrb_ary_new(mrb) : mrb_ary_new_capa(mrb, 0));
1173
1174 if (interrupt_flag == 0) {
1175 if (rp) {
1176 list = RARRAY_PTR(result)[0];
1177 for (i = 0; i < RARRAY_LEN(read); i++) {
1178 fptr = io_get_open_fptr(mrb, RARRAY_PTR(read)[i]);
1179 if (FD_ISSET(fptr->fd, rp) ||
1180 FD_ISSET(fptr->fd, &pset)) {
1181 mrb_ary_push(mrb, list, RARRAY_PTR(read)[i]);
1182 }
1183 }
1184 }
1185
1186 if (wp) {
1187 list = RARRAY_PTR(result)[1];
1188 for (i = 0; i < RARRAY_LEN(write); i++) {
1189 fptr = io_get_open_fptr(mrb, RARRAY_PTR(write)[i]);
1190 if (FD_ISSET(fptr->fd, wp)) {
1191 mrb_ary_push(mrb, list, RARRAY_PTR(write)[i]);
1192 } else if (fptr->fd2 >= 0 && FD_ISSET(fptr->fd2, wp)) {
1193 mrb_ary_push(mrb, list, RARRAY_PTR(write)[i]);
1194 }
1195 }
1196 }
1197
1198 if (ep) {
1199 list = RARRAY_PTR(result)[2];
1200 for (i = 0; i < RARRAY_LEN(except); i++) {
1201 fptr = io_get_open_fptr(mrb, RARRAY_PTR(except)[i]);
1202 if (FD_ISSET(fptr->fd, ep)) {
1203 mrb_ary_push(mrb, list, RARRAY_PTR(except)[i]);
1204 } else if (fptr->fd2 >= 0 && FD_ISSET(fptr->fd2, ep)) {
1205 mrb_ary_push(mrb, list, RARRAY_PTR(except)[i]);
1206 }
1207 }
1208 }
1209 }
1210
1211 return result;
1212 }
1213
1214 mrb_value
mrb_io_fileno(mrb_state * mrb,mrb_value io)1215 mrb_io_fileno(mrb_state *mrb, mrb_value io)
1216 {
1217 struct mrb_io *fptr;
1218 fptr = io_get_open_fptr(mrb, io);
1219 return mrb_fixnum_value(fptr->fd);
1220 }
1221
1222 mrb_value
mrb_io_close_on_exec_p(mrb_state * mrb,mrb_value self)1223 mrb_io_close_on_exec_p(mrb_state *mrb, mrb_value self)
1224 {
1225 #if defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
1226 struct mrb_io *fptr;
1227 int ret;
1228
1229 fptr = io_get_open_fptr(mrb, self);
1230
1231 if (fptr->fd2 >= 0) {
1232 if ((ret = fcntl(fptr->fd2, F_GETFD)) == -1) mrb_sys_fail(mrb, "F_GETFD failed");
1233 if (!(ret & FD_CLOEXEC)) return mrb_false_value();
1234 }
1235
1236 if ((ret = fcntl(fptr->fd, F_GETFD)) == -1) mrb_sys_fail(mrb, "F_GETFD failed");
1237 if (!(ret & FD_CLOEXEC)) return mrb_false_value();
1238 return mrb_true_value();
1239
1240 #else
1241 mrb_raise(mrb, E_NOTIMP_ERROR, "IO#close_on_exec? is not supported on the platform");
1242 return mrb_false_value();
1243 #endif
1244 }
1245
1246 mrb_value
mrb_io_set_close_on_exec(mrb_state * mrb,mrb_value self)1247 mrb_io_set_close_on_exec(mrb_state *mrb, mrb_value self)
1248 {
1249 #if defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
1250 struct mrb_io *fptr;
1251 int flag, ret;
1252 mrb_bool b;
1253
1254 fptr = io_get_open_fptr(mrb, self);
1255 mrb_get_args(mrb, "b", &b);
1256 flag = b ? FD_CLOEXEC : 0;
1257
1258 if (fptr->fd2 >= 0) {
1259 if ((ret = fcntl(fptr->fd2, F_GETFD)) == -1) mrb_sys_fail(mrb, "F_GETFD failed");
1260 if ((ret & FD_CLOEXEC) != flag) {
1261 ret = (ret & ~FD_CLOEXEC) | flag;
1262 ret = fcntl(fptr->fd2, F_SETFD, ret);
1263
1264 if (ret == -1) mrb_sys_fail(mrb, "F_SETFD failed");
1265 }
1266 }
1267
1268 if ((ret = fcntl(fptr->fd, F_GETFD)) == -1) mrb_sys_fail(mrb, "F_GETFD failed");
1269 if ((ret & FD_CLOEXEC) != flag) {
1270 ret = (ret & ~FD_CLOEXEC) | flag;
1271 ret = fcntl(fptr->fd, F_SETFD, ret);
1272 if (ret == -1) mrb_sys_fail(mrb, "F_SETFD failed");
1273 }
1274
1275 return mrb_bool_value(b);
1276 #else
1277 mrb_raise(mrb, E_NOTIMP_ERROR, "IO#close_on_exec= is not supported on the platform");
1278 return mrb_nil_value();
1279 #endif
1280 }
1281
1282 mrb_value
mrb_io_set_sync(mrb_state * mrb,mrb_value self)1283 mrb_io_set_sync(mrb_state *mrb, mrb_value self)
1284 {
1285 struct mrb_io *fptr;
1286 mrb_bool b;
1287
1288 fptr = io_get_open_fptr(mrb, self);
1289 mrb_get_args(mrb, "b", &b);
1290 fptr->sync = b;
1291 return mrb_bool_value(b);
1292 }
1293
1294 mrb_value
mrb_io_sync(mrb_state * mrb,mrb_value self)1295 mrb_io_sync(mrb_state *mrb, mrb_value self)
1296 {
1297 struct mrb_io *fptr;
1298 fptr = io_get_open_fptr(mrb, self);
1299 return mrb_bool_value(fptr->sync);
1300 }
1301
1302 void
mrb_init_io(mrb_state * mrb)1303 mrb_init_io(mrb_state *mrb)
1304 {
1305 struct RClass *io;
1306
1307 io = mrb_define_class(mrb, "IO", mrb->object_class);
1308 MRB_SET_INSTANCE_TT(io, MRB_TT_DATA);
1309
1310 mrb_include_module(mrb, io, mrb_module_get(mrb, "Enumerable")); /* 15.2.20.3 */
1311 mrb_define_class_method(mrb, io, "_popen", mrb_io_s_popen, MRB_ARGS_ANY());
1312 mrb_define_class_method(mrb, io, "_sysclose", mrb_io_s_sysclose, MRB_ARGS_REQ(1));
1313 mrb_define_class_method(mrb, io, "for_fd", mrb_io_s_for_fd, MRB_ARGS_ANY());
1314 mrb_define_class_method(mrb, io, "select", mrb_io_s_select, MRB_ARGS_ANY());
1315 mrb_define_class_method(mrb, io, "sysopen", mrb_io_s_sysopen, MRB_ARGS_ANY());
1316 #if !defined(_WIN32) && !(defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE)
1317 mrb_define_class_method(mrb, io, "_pipe", mrb_io_s_pipe, MRB_ARGS_NONE());
1318 #endif
1319
1320 mrb_define_method(mrb, io, "initialize", mrb_io_initialize, MRB_ARGS_ANY()); /* 15.2.20.5.21 (x)*/
1321 mrb_define_method(mrb, io, "initialize_copy", mrb_io_initialize_copy, MRB_ARGS_REQ(1));
1322 mrb_define_method(mrb, io, "_check_readable", mrb_io_check_readable, MRB_ARGS_NONE());
1323 mrb_define_method(mrb, io, "isatty", mrb_io_isatty, MRB_ARGS_NONE());
1324 mrb_define_method(mrb, io, "sync", mrb_io_sync, MRB_ARGS_NONE());
1325 mrb_define_method(mrb, io, "sync=", mrb_io_set_sync, MRB_ARGS_REQ(1));
1326 mrb_define_method(mrb, io, "sysread", mrb_io_sysread, MRB_ARGS_ANY());
1327 mrb_define_method(mrb, io, "sysseek", mrb_io_sysseek, MRB_ARGS_REQ(1));
1328 mrb_define_method(mrb, io, "syswrite", mrb_io_syswrite, MRB_ARGS_REQ(1));
1329 mrb_define_method(mrb, io, "close", mrb_io_close, MRB_ARGS_NONE()); /* 15.2.20.5.1 */
1330 mrb_define_method(mrb, io, "close_write", mrb_io_close_write, MRB_ARGS_NONE());
1331 mrb_define_method(mrb, io, "close_on_exec=", mrb_io_set_close_on_exec, MRB_ARGS_REQ(1));
1332 mrb_define_method(mrb, io, "close_on_exec?", mrb_io_close_on_exec_p, MRB_ARGS_NONE());
1333 mrb_define_method(mrb, io, "closed?", mrb_io_closed, MRB_ARGS_NONE()); /* 15.2.20.5.2 */
1334 mrb_define_method(mrb, io, "pid", mrb_io_pid, MRB_ARGS_NONE()); /* 15.2.20.5.2 */
1335 mrb_define_method(mrb, io, "fileno", mrb_io_fileno, MRB_ARGS_NONE());
1336
1337
1338 mrb_gv_set(mrb, mrb_intern_cstr(mrb, "$/"), mrb_str_new_cstr(mrb, "\n"));
1339 }
1340