1 /*
2 Copyright (C) 2001-2014, Parrot Foundation.
3 
4 =head1 NAME
5 
6 src/io/api.c - Parrot I/O API
7 
8 =head1 DESCRIPTION
9 
10 The Parrot I/O subsystem provides the core I/O functionality for all parts of
11 Parrot. This file implements the public interface to the I/O subsystem.
12 
13 =head1 Functions
14 
15 =over 4
16 
17 =cut
18 
19 */
20 
21 #include "parrot/parrot.h"
22 #include "parrot/extend.h"
23 #include "io_private.h"
24 #include "api.str"
25 #include "pmc/pmc_handle.h"
26 #include "pmc/pmc_filehandle.h"
27 #include "pmc/pmc_stringhandle.h"
28 #include "pmc/pmc_socket.h"
29 #include "pmc/pmc_sockaddr.h"
30 #include "pmc/pmc_bytebuffer.h"
31 
32 #include <stdarg.h>
33 
34 PIOOFF_T piooffsetzero;
35 
36 /* HEADERIZER HFILE: include/parrot/io.h */
37 /* HEADERIZER BEGIN: static */
38 /* HEADERIZER END: static */
39 
40 /*
41 
42 =item C<void Parrot_io_init(PARROT_INTERP)>
43 
44 Sets up the interpreter's I/O storage and creates the C<STD*> handles.
45 
46 Called when creating an interpreter.
47 
48 =item C<void io_setup_vtables(PARROT_INTERP)>
49 
50 Called during PIO subsystem initialization. This creates the vtables for
51 FileHandle, Pipe, Socket, StringHandle and UserHandle.
52 
53 =cut
54 
55 */
56 
57 PARROT_EXPORT
58 void
Parrot_io_init(PARROT_INTERP)59 Parrot_io_init(PARROT_INTERP)
60 {
61     ASSERT_ARGS(Parrot_io_init)
62     /* Has interp been initialized already? */
63     if (interp->piodata) {
64         /* memsub system is up and running: */
65         /* Init IO stacks and handles for interp instance.  */
66         PIOHANDLE os_handle;
67         PMC *handle;
68 
69         io_setup_vtables(interp);
70 
71         os_handle = Parrot_io_internal_std_os_handle(interp, PIO_STDIN_FILENO);
72         handle    = Parrot_io_fdopen_flags(interp, PMCNULL, os_handle, PIO_F_READ);
73         Parrot_io_buffer_add_to_handle(interp, handle, IO_PTR_IDX_READ_BUFFER, BUFFER_SIZE_ANY,
74                                        PIO_BF_BLKBUF);
75         _PIO_STDIN(interp) = handle;
76 
77         os_handle = Parrot_io_internal_std_os_handle(interp, PIO_STDOUT_FILENO);
78         handle    = Parrot_io_fdopen_flags(interp, PMCNULL, os_handle, PIO_F_WRITE);
79         /* Parrot_io_buffer_add_to_handle(interp, handle, IO_PTR_IDX_WRITE_BUFFER, BUFFER_SIZE_ANY,
80                                        PIO_BF_LINEBUF); */
81         _PIO_STDOUT(interp) = handle;
82 
83         os_handle           = Parrot_io_internal_std_os_handle(interp, PIO_STDERR_FILENO);
84         _PIO_STDERR(interp) = Parrot_io_fdopen_flags(interp, PMCNULL,
85                                 os_handle, PIO_F_WRITE);
86 
87         if (Interp_debug_TEST(interp, PARROT_START_DEBUG_FLAG)) {
88             Parrot_io_eprintf(NULL, "I/O system initialized.\n");
89         }
90 
91         return;
92     }
93 
94     interp->piodata = mem_gc_allocate_zeroed_typed(interp, ParrotIOData);
95     if (interp->piodata == NULL)
96         Parrot_ex_throw_from_c_noargs(interp, EXCEPTION_PIO_ERROR,
97             "PIO alloc piodata failure");
98     interp->piodata->table         =
99             mem_gc_allocate_n_zeroed_typed(interp, PIO_NR_OPEN, PMC *);
100 
101     if (!interp->piodata->table)
102         Parrot_ex_throw_from_c_noargs(interp, EXCEPTION_PIO_ERROR,
103             "PIO alloc table failure");
104 }
105 
106 void
io_setup_vtables(PARROT_INTERP)107 io_setup_vtables(PARROT_INTERP)
108 {
109     ASSERT_ARGS(io_setup_vtables)
110     const int number_of_vtables = 5;
111     interp->piodata->vtables = (IO_VTABLE*)mem_gc_allocate_n_zeroed_typed(interp,
112                                    number_of_vtables, IO_VTABLE);
113     interp->piodata->num_vtables = number_of_vtables;
114     io_filehandle_setup_vtable(interp, NULL, IO_VTABLE_FILEHANDLE);
115     io_socket_setup_vtable(interp, NULL, IO_VTABLE_SOCKET);
116     io_pipe_setup_vtable(interp, NULL, IO_VTABLE_PIPE);
117     io_stringhandle_setup_vtable(interp, NULL, IO_VTABLE_STRINGHANDLE);
118     io_userhandle_setup_vtable(interp, NULL, IO_VTABLE_USER);
119 }
120 
121 /*
122 
123 =item C<const IO_VTABLE * Parrot_io_allocate_new_vtable(PARROT_INTERP, const
124 char *name)>
125 
126 Allocates a new IO_VTABLE * structure with the given name.
127 
128 =item C<const IO_VTABLE * Parrot_io_get_vtable(PARROT_INTERP, INTVAL idx, const
129 char * name)>
130 
131 Retrieves the vtable at index C<idx>. If C<idx> is -1, the vtable is instead
132 searched for by C<name>. Notice that name lookups are much slower.
133 
134 =cut
135 
136 */
137 
138 PARROT_CANNOT_RETURN_NULL
139 PARROT_WARN_UNUSED_RESULT
140 PARROT_MALLOC
141 const IO_VTABLE *
Parrot_io_allocate_new_vtable(PARROT_INTERP,ARGIN (const char * name))142 Parrot_io_allocate_new_vtable(PARROT_INTERP, ARGIN(const char *name))
143 {
144     ASSERT_ARGS(Parrot_io_allocate_new_vtable)
145     const int number_of_vtables = interp->piodata->num_vtables;
146     IO_VTABLE *vtable;
147     interp->piodata->vtables = mem_gc_realloc_n_typed(interp,
148                                 interp->piodata->vtables,
149                                 number_of_vtables + 1, IO_VTABLE);
150     vtable = IO_EDITABLE_IO_VTABLE(interp, number_of_vtables);
151     vtable->name = name;
152     vtable->number = number_of_vtables;
153     interp->piodata->num_vtables++;
154     return vtable;
155 }
156 
157 PARROT_EXPORT
158 PARROT_WARN_UNUSED_RESULT
159 PARROT_CAN_RETURN_NULL
160 const IO_VTABLE *
Parrot_io_get_vtable(PARROT_INTERP,INTVAL idx,ARGIN_NULLOK (const char * name))161 Parrot_io_get_vtable(PARROT_INTERP, INTVAL idx, ARGIN_NULLOK(const char * name))
162 {
163     ASSERT_ARGS(Parrot_io_get_vtable)
164     INTVAL i;
165     if (idx >= interp->piodata->num_vtables)
166         Parrot_ex_throw_from_c_args(interp, NULL, EXCEPTION_PIO_ERROR,
167             "Cannot get IO VTABLE %d", idx);
168     if (idx >= 0)
169         return &(interp->piodata->vtables[idx]);
170     if (!name)
171         Parrot_ex_throw_from_c_noargs(interp, EXCEPTION_PIO_ERROR,
172             "Cannot get IO VTABLE with no index and no name");
173 
174     for (i = 0; i < interp->piodata->num_vtables; i++) {
175         if (!strcmp(name, interp->piodata->vtables[i].name))
176             return &(interp->piodata->vtables[i]);
177     }
178     Parrot_ex_throw_from_c_args(interp, NULL, EXCEPTION_PIO_ERROR,
179             "Cannot get IO VTABLE %s", name);
180     return NULL;
181 }
182 
183 /*
184 
185 =item C<void Parrot_io_finish(PARROT_INTERP)>
186 
187 Closes the interpreter's IO resources.  Called during its interpreter
188 destruction.
189 
190 =cut
191 
192 */
193 
194 PARROT_EXPORT
195 void
Parrot_io_finish(PARROT_INTERP)196 Parrot_io_finish(PARROT_INTERP)
197 {
198     ASSERT_ARGS(Parrot_io_finish)
199     /*
200      * TODO free IO of std-handles
201      */
202     Parrot_io_flush(interp, _PIO_STDOUT(interp));
203     mem_gc_free(interp, interp->piodata->table);
204     interp->piodata->table = NULL;
205     mem_gc_free(interp, interp->piodata);
206     interp->piodata = NULL;
207 
208 }
209 
210 /*
211 
212 =item C<void Parrot_io_mark(PARROT_INTERP, ParrotIOData *piodata)>
213 
214 Called from C<Parrot_gc_trace_root()> to mark the standard IO handles
215 (C<stdin>, C<stdout> and C<stderr>) and other global data for the IO
216 subsystem.
217 
218 =cut
219 
220 */
221 
222 void
Parrot_io_mark(PARROT_INTERP,ARGIN (ParrotIOData * piodata))223 Parrot_io_mark(PARROT_INTERP, ARGIN(ParrotIOData *piodata))
224 {
225     ASSERT_ARGS(Parrot_io_mark)
226     INTVAL i;
227     PMC ** const table = piodata->table;
228 
229     /* PIO_NR_OPEN is now 3 */
230     for (i = 0; i < PIO_NR_OPEN; ++i) {
231         Parrot_gc_mark_PMC_alive(interp, table[i]);
232     }
233 }
234 
235 /*
236 
237 =back
238 
239 =head2 Generic I/O interface
240 
241 =over 4
242 
243 =cut
244 
245 */
246 
247 /*
248 
249 =item C<PMC * Parrot_io_stdhandle(PARROT_INTERP, INTVAL fileno, PMC *newhandle)>
250 
251 Get the current standard IO object with the specified filenumber. If the
252 C<newhandle> parameter is non-null, set that to be the new standard IO object
253 of that number. Returns the old IO object before the new one is set, so it
254 can be cached for later.
255 
256 =cut
257 
258 */
259 
260 PARROT_EXPORT
261 PARROT_WARN_UNUSED_RESULT
262 PARROT_CAN_RETURN_NULL
263 PMC *
Parrot_io_stdhandle(PARROT_INTERP,INTVAL fileno,ARGIN_NULLOK (PMC * newhandle))264 Parrot_io_stdhandle(PARROT_INTERP, INTVAL fileno, ARGIN_NULLOK(PMC *newhandle))
265 {
266     ASSERT_ARGS(Parrot_io_stdhandle)
267     PMC * result = PMCNULL;
268     if (fileno == PIO_STDIN_FILENO || fileno == PIO_STDOUT_FILENO ||
269             fileno == PIO_STDERR_FILENO) {
270         result = interp->piodata->table[fileno];
271         if (! PMC_IS_NULL(newhandle))
272             interp->piodata->table[fileno] = newhandle;
273     }
274     return result;
275 }
276 
277 
278 /*
279 
280 =item C<PMC * Parrot_io_open(PARROT_INTERP, PMC *pmc, STRING *path, STRING
281 *mode)>
282 
283 Open the given handle C<pmc> with the given C<path> and C<mode> strings. If
284 C<pmc> is null, create a new FileHandle PMC or whatever is currently mapped
285 to FileHandle for opening. Notice that C<path> and C<mode> may not be required
286 for all types and may be type-dependent.
287 
288 =item C<PMC * Parrot_io_open_handle(PARROT_INTERP, PMC *pmc, STRING *path,
289 STRING *mode)>
290 
291 Legacy wrapper for Parrot_io_open(). Do not use. This is deprecated.
292 
293 =cut
294 
295 */
296 
297 PARROT_EXPORT
298 PARROT_WARN_UNUSED_RESULT
299 PARROT_CANNOT_RETURN_NULL
300 PARROT_DEPRECATED
301 PMC *
Parrot_io_open_handle(PARROT_INTERP,ARGIN (PMC * pmc),ARGIN (STRING * path),ARGIN (STRING * mode))302 Parrot_io_open_handle(PARROT_INTERP, ARGIN(PMC *pmc), ARGIN(STRING *path),
303         ARGIN(STRING *mode))
304 {
305     ASSERT_ARGS(Parrot_io_open_handle)
306     return Parrot_io_open(interp, pmc, path, mode);
307 }
308 
309 
310 PARROT_EXPORT
311 PARROT_WARN_UNUSED_RESULT
312 PARROT_CANNOT_RETURN_NULL
313 PMC *
Parrot_io_open(PARROT_INTERP,ARGIN (PMC * pmc),ARGIN (STRING * path),ARGIN (STRING * mode))314 Parrot_io_open(PARROT_INTERP, ARGIN(PMC *pmc), ARGIN(STRING *path),
315         ARGIN(STRING *mode))
316 {
317     ASSERT_ARGS(Parrot_io_open)
318     PMC *handle;
319     const IO_VTABLE * vtable;
320 
321     /* If a handle is not provided, create a new FileHandle */
322     if (PMC_IS_NULL(pmc))
323         handle = io_get_new_filehandle(interp);
324     else
325         handle = pmc;
326     PARROT_ASSERT(!PMC_IS_NULL(handle));
327     vtable = IO_GET_VTABLE(interp, handle);
328 
329     /* Unless flagged otherwise, a path is required for open */
330     if ((vtable->flags & PIO_VF_PATH_NOT_REQUIRED) == 0 && STRING_IS_NULL(path))
331         Parrot_ex_throw_from_c_args(interp, NULL, EXCEPTION_PIO_ERROR,
332                         "Cannot open %s, no path", vtable->name);
333 
334     /* If not specified, default to read mode */
335     if (STRING_IS_NULL(mode))
336         mode = CONST_STRING(interp, "r");
337 
338     {
339         const INTVAL flags = Parrot_io_parse_open_flags(interp, mode);
340         INTVAL status = vtable->open(interp, handle, path, flags, mode);
341 
342         if (!status)
343             Parrot_ex_throw_from_c_args(interp, NULL, EXCEPTION_PIO_ERROR,
344                 "Unable to open %s from path '%Ss'", vtable->name, path);
345 
346         /* If this type uses buffers by default, set them up, and if we're
347            in an acceptable mode, set up buffers. */
348         if (vtable->flags & PIO_VF_DEFAULT_READ_BUF && flags & PIO_F_READ)
349             Parrot_io_buffer_add_to_handle(interp, handle, IO_PTR_IDX_READ_BUFFER, BUFFER_SIZE_ANY,
350                                            PIO_BF_BLKBUF);
351         if (vtable->flags & PIO_VF_DEFAULT_WRITE_BUF && flags & PIO_F_WRITE)
352             Parrot_io_buffer_add_to_handle(interp, handle, IO_PTR_IDX_WRITE_BUFFER, BUFFER_SIZE_ANY,
353                                            PIO_BF_BLKBUF);
354     }
355 
356     return handle;
357 }
358 
359 /*
360 
361 =item C<PMC * Parrot_io_socket(PARROT_INTERP, PMC *socket, INTVAL fam, INTVAL
362 type, INTVAL proto)>
363 
364 Create a low-level socket structure and add it to the C<socket> PMC. if
365 C<socket> is null, create a new Socket PMC (or whatever is mapped to it).
366 Use the given C<fam>, C<type> and C<proto> values to configure the new socket.
367 Returns the C<socket>.
368 
369 =item C<INTVAL Parrot_io_socket_handle(PARROT_INTERP, PMC *socket, INTVAL fam,
370 INTVAL type, INTVAL proto)>
371 
372 Legacy wrapper function for Parrot_io_socket. This is deprecated, do not use.
373 
374 =cut
375 
376 */
377 
378 PARROT_EXPORT
379 PARROT_WARN_UNUSED_RESULT
380 PARROT_DEPRECATED
381 INTVAL
Parrot_io_socket_handle(PARROT_INTERP,ARGMOD_NULLOK (PMC * socket),INTVAL fam,INTVAL type,INTVAL proto)382 Parrot_io_socket_handle(PARROT_INTERP, ARGMOD_NULLOK(PMC *socket), INTVAL fam,
383             INTVAL type, INTVAL proto)
384 {
385     ASSERT_ARGS(Parrot_io_socket_handle)
386     socket = Parrot_io_socket(interp, socket, fam, type, proto);
387     /* For historical reasons, this function always returns 0 to signal
388        unconditional success */
389     return 0;
390 }
391 
392 PARROT_EXPORT
393 PARROT_WARN_UNUSED_RESULT
394 PARROT_CANNOT_RETURN_NULL
395 PMC *
Parrot_io_socket(PARROT_INTERP,ARGMOD_NULLOK (PMC * socket),INTVAL fam,INTVAL type,INTVAL proto)396 Parrot_io_socket(PARROT_INTERP, ARGMOD_NULLOK(PMC *socket), INTVAL fam,
397             INTVAL type, INTVAL proto)
398 {
399     ASSERT_ARGS(Parrot_io_socket)
400     PMC       *new_socket;
401     PIOHANDLE  os_handle;
402 
403     if (PMC_IS_NULL(socket))
404         new_socket = io_get_new_socket(interp);
405     else
406         new_socket = socket;
407 
408     /* TODO: Move this logic into src/io/socket.c */
409 
410     os_handle = Parrot_io_internal_socket(interp, fam, type, proto);
411 
412     SETATTR_Socket_os_handle(interp, new_socket, os_handle);
413     SETATTR_Socket_family(interp, new_socket, fam);
414     SETATTR_Socket_type(interp, new_socket, type);
415     SETATTR_Socket_protocol(interp, new_socket, proto);
416 
417     /* TODO: How do we signal errors here? */
418 
419     return socket;
420 }
421 
422 /*
423 
424 =item C<PMC * Parrot_io_fdopen(PARROT_INTERP, PMC *pmc, PIOHANDLE fd, STRING
425 *sflags)>
426 
427 Creates and returns a C<FileHandle> PMC for a given set of flags on an
428 existing, open file descriptor.
429 
430 This is used particularly to initialize the C<STD*> IO handles onto the
431 OS IO handles (0, 1, 2).
432 
433 =cut
434 
435 */
436 
437 PARROT_EXPORT
438 PARROT_WARN_UNUSED_RESULT
439 PARROT_CANNOT_RETURN_NULL
440 PMC *
Parrot_io_fdopen(PARROT_INTERP,ARGIN (PMC * pmc),PIOHANDLE fd,ARGIN (STRING * sflags))441 Parrot_io_fdopen(PARROT_INTERP, ARGIN(PMC *pmc), PIOHANDLE fd, ARGIN(STRING *sflags))
442 {
443     ASSERT_ARGS(Parrot_io_fdopen)
444     const INTVAL flags = Parrot_io_parse_open_flags(interp, sflags);
445     return Parrot_io_fdopen_flags(interp, pmc, fd, flags);
446 }
447 
448 /*
449 
450 =item C<PMC * Parrot_io_fdopen_flags(PARROT_INTERP, PMC *filehandle, PIOHANDLE
451 fd, INTVAL flags)>
452 
453 Creates and returns a C<FileHandle> PMC for a given set of flags on an
454 existing, open file descriptor.
455 
456 This is used particularly to initialize the C<STD*> IO handles onto the
457 OS IO handles (0, 1, 2).
458 
459 =cut
460 
461 */
462 
463 PARROT_EXPORT
464 PARROT_WARN_UNUSED_RESULT
465 PARROT_CANNOT_RETURN_NULL
466 PMC *
Parrot_io_fdopen_flags(PARROT_INTERP,ARGMOD (PMC * filehandle),PIOHANDLE fd,INTVAL flags)467 Parrot_io_fdopen_flags(PARROT_INTERP, ARGMOD(PMC *filehandle), PIOHANDLE fd,
468         INTVAL flags)
469 {
470     ASSERT_ARGS(Parrot_io_fdopen_flags)
471 
472     if (!flags)
473         return PMCNULL;
474 
475     if (Parrot_io_internal_is_tty(interp, fd))
476         flags |= PIO_F_CONSOLE;
477 
478     /* fdopened files are always shared */
479     flags |= PIO_F_SHARED;
480 
481     if (PMC_IS_NULL(filehandle))
482         filehandle = io_get_new_filehandle(interp);
483 
484     {
485         const IO_VTABLE * const vtable = IO_GET_VTABLE(interp, filehandle);
486         if (vtable->number != IO_VTABLE_FILEHANDLE && vtable->number != IO_VTABLE_PIPE)
487             Parrot_ex_throw_from_c_args(interp, NULL, EXCEPTION_PIO_ERROR,
488                     "Cannot set an OS file descriptor to a %s PMC", vtable->name);
489         vtable->set_flags(interp, filehandle, flags);
490         io_filehandle_set_os_handle(interp, filehandle, fd);
491     }
492 
493     return filehandle;
494 }
495 
496 /*
497 
498 =item C<void Parrot_io_socket_initialize(PARROT_INTERP, PMC *socket)>
499 
500 Initialize a Socket PMC by clearing it's C<os_handle> and marking it as being
501 disconnected (closed).
502 
503 =cut
504 
505 */
506 
507 PARROT_EXPORT
508 void
Parrot_io_socket_initialize(SHIM_INTERP,ARGMOD (PMC * socket))509 Parrot_io_socket_initialize(SHIM_INTERP, ARGMOD(PMC *socket))
510 {
511     ASSERT_ARGS(Parrot_io_socket_initialize)
512     /* TODO: Move this logic into src/io/socket.c */
513     PARROT_SOCKET(socket)->os_handle = (PIOHANDLE)PIO_INVALID_HANDLE;
514 }
515 
516 /*
517 
518 =item C<INTVAL Parrot_io_close(PARROT_INTERP, PMC *handle, INTVAL autoflush)>
519 
520 Closes the Handle object C<pmc>. If C<autoflush> is C<1>, flush the handle.
521 If it is C<-1> use type-specific default behavior to determine whether we
522 flush or not. If it is C<0> do not flush the handle before closing. Notice
523 that buffers are flushed to the handle no matter what, but the handle may
524 not also be flushed. This may cause problems for e.g. file descriptors that
525 may require to be flushed at the OS level before closing to ensure that data
526 is delivered.
527 
528 =item C<INTVAL Parrot_io_close_handle(PARROT_INTERP, PMC *pmc)>
529 
530 Legacy wrapper for C<Parrot_io_close>. Deprecated. Do not use.
531 
532 =cut
533 
534 */
535 
536 PARROT_EXPORT
537 PARROT_DEPRECATED
538 INTVAL
Parrot_io_close_handle(PARROT_INTERP,ARGMOD (PMC * pmc))539 Parrot_io_close_handle(PARROT_INTERP, ARGMOD(PMC *pmc))
540 {
541     ASSERT_ARGS(Parrot_io_close_handle)
542     return Parrot_io_close(interp, pmc, -1);
543 }
544 
545 PARROT_EXPORT
546 INTVAL
Parrot_io_close(PARROT_INTERP,ARGMOD (PMC * handle),INTVAL autoflush)547 Parrot_io_close(PARROT_INTERP, ARGMOD(PMC *handle), INTVAL autoflush)
548 {
549     ASSERT_ARGS(Parrot_io_close)
550     if (PMC_IS_NULL(handle))
551         return 0;
552     else {
553         const IO_VTABLE * const vtable = IO_GET_VTABLE(interp, handle);
554         IO_BUFFER * const write_buffer = IO_GET_WRITE_BUFFER(interp, handle);
555         IO_BUFFER * const read_buffer = IO_GET_READ_BUFFER(interp, handle);
556         if (write_buffer)
557             Parrot_io_buffer_flush(interp, write_buffer, handle, vtable);
558         if (read_buffer)
559             Parrot_io_buffer_clear(interp, read_buffer);
560 
561         /* TODO: We need to better-document the autoflush values, and maybe
562            turn it into an enum or a series of typedefs */
563         if (autoflush == -1)
564             autoflush = (vtable->flags & PIO_VF_FLUSH_ON_CLOSE) ? 1 : 0;
565         if (autoflush == 1)
566             vtable->flush(interp, handle);
567         return vtable->close(interp, handle);
568     }
569 }
570 
571 /*
572 
573 =item C<INTVAL Parrot_io_is_closed(PARROT_INTERP, PMC *pmc)>
574 
575 Test whether the handle C<pmc> is closed. Return C<1> if it is closed, C<0>
576 otherwise. If C<pmc> is NULL or not a valid handle, it may always return
577 C<1>.
578 
579 =cut
580 
581 */
582 
583 PARROT_EXPORT
584 PARROT_WARN_UNUSED_RESULT
585 INTVAL
Parrot_io_is_closed(PARROT_INTERP,ARGIN (PMC * pmc))586 Parrot_io_is_closed(PARROT_INTERP, ARGIN(PMC *pmc))
587 {
588     ASSERT_ARGS(Parrot_io_is_closed)
589 
590     if (PMC_IS_NULL(pmc))
591         return 1;
592 
593     else {
594         const IO_VTABLE * const vtable = IO_GET_VTABLE(interp, pmc);
595         return !vtable->is_open(interp, pmc);
596     }
597 }
598 
599 /*
600 
601 =item C<size_t Parrot_io_flush(PARROT_INTERP, PMC *handle)>
602 
603 Flush the handle C<pmc>. Write buffers are flushed to the handle first, then
604 the handle is flushed. Notice that read buffers are not modified.
605 
606 =item C<void Parrot_io_flush_handle(PARROT_INTERP, PMC *pmc)>
607 
608 Flush the handle. This is a legacy wrapper function and is deprecated. Use
609 Parrot_io_flush instead.
610 
611 =cut
612 
613 */
614 
615 PARROT_EXPORT
616 PARROT_DEPRECATED
617 void
Parrot_io_flush_handle(PARROT_INTERP,ARGMOD (PMC * pmc))618 Parrot_io_flush_handle(PARROT_INTERP, ARGMOD(PMC *pmc))
619 {
620     ASSERT_ARGS(Parrot_io_flush_handle)
621     Parrot_io_flush(interp, pmc);
622 }
623 
624 PARROT_EXPORT
625 size_t
Parrot_io_flush(PARROT_INTERP,ARGMOD (PMC * handle))626 Parrot_io_flush(PARROT_INTERP, ARGMOD(PMC *handle))
627 {
628     ASSERT_ARGS(Parrot_io_flush)
629 
630     if (PMC_IS_NULL(handle))
631         return 0;
632 
633     if (Parrot_io_is_closed(interp, handle))
634         Parrot_ex_throw_from_c_noargs(interp, EXCEPTION_PIO_ERROR,
635                 "Cannot flush a closed handle");
636 
637     else {
638         const IO_VTABLE * const vtable = IO_GET_VTABLE(interp, handle);
639         IO_BUFFER * const write_buffer = IO_GET_WRITE_BUFFER(interp, handle);
640         if (write_buffer)
641             Parrot_io_buffer_flush(interp, write_buffer, handle, vtable);
642         return vtable->flush(interp, handle);
643     }
644 }
645 
646 /*
647 
648 =item C<STRING * Parrot_io_read_s(PARROT_INTERP, PMC *handle, size_t length)>
649 
650 Return a new C<STRING *> containing C<length> characters read from handle
651 C<pmc>. Notice that the number of bytes read may be more than the number of
652 characters requested for multi-byte encodings. Notice that incomplete
653 codepoints will not be included in the returned string.
654 
655 This routine will throw an exception if the handle C<pmc> is null or if it is
656 not opened for reading.
657 
658 Notice that this routine may automatically add a read buffer to the handle if
659 required for multi-byte encodings.
660 
661 =item C<STRING * Parrot_io_reads(PARROT_INTERP, PMC *pmc, size_t length)>
662 
663 This is a legacy wrapper for C<Parrot_io_read_s>. Do not use. This is deprecated.
664 
665 =item C<STRING * Parrot_io_recv_handle(PARROT_INTERP, PMC *pmc, size_t len)>
666 
667 A legacy wrapper around C<Parrot_io_read_s>, typically used for sockets.
668 Deprecated. Do not use.
669 
670 =cut
671 
672 */
673 
674 PARROT_EXPORT
675 PARROT_WARN_UNUSED_RESULT
676 PARROT_CANNOT_RETURN_NULL
677 PARROT_DEPRECATED
678 STRING *
Parrot_io_reads(PARROT_INTERP,ARGMOD (PMC * pmc),size_t length)679 Parrot_io_reads(PARROT_INTERP, ARGMOD(PMC *pmc), size_t length)
680 {
681     ASSERT_ARGS(Parrot_io_reads)
682     return Parrot_io_read_s(interp, pmc, length);
683 }
684 
685 PARROT_EXPORT
686 PARROT_WARN_UNUSED_RESULT
687 PARROT_CANNOT_RETURN_NULL
688 STRING *
Parrot_io_read_s(PARROT_INTERP,ARGMOD (PMC * handle),size_t length)689 Parrot_io_read_s(PARROT_INTERP, ARGMOD(PMC *handle), size_t length)
690 {
691     ASSERT_ARGS(Parrot_io_read_s)
692 
693     if (PMC_IS_NULL(handle))
694         Parrot_ex_throw_from_c_noargs(interp, EXCEPTION_PIO_ERROR,
695             "Attempt to read from null or invalid PMC");
696 
697     if (!length)
698         return STRINGNULL;
699 
700     {
701         const IO_VTABLE * const vtable = IO_GET_VTABLE(interp, handle);
702         IO_BUFFER *       read_buffer  = IO_GET_READ_BUFFER(interp, handle);
703         IO_BUFFER * const write_buffer = IO_GET_WRITE_BUFFER(interp, handle);
704         const STR_VTABLE * encoding    = vtable->get_encoding(interp, handle);
705         STRING * s;
706 
707         Parrot_block_GC_move(interp); /* Our local strings may not move away. GH #1196 */
708         /* read_s requires us to read in a whole number of characters, which
709            might be multi-byte. This requires a read buffer. */
710         /* TODO: If we have a fixed8 encoding or similar, we should be able to
711            avoid using a read_buffer here. Detect that case and don't assign
712            a buffer if not needed. */
713         if (read_buffer == NULL)
714             read_buffer = io_verify_has_read_buffer(interp, handle, vtable, BUFFER_SIZE_ANY);
715         io_verify_is_open_for(interp, handle, vtable, PIO_F_READ);
716         io_sync_buffers_for_read(interp, handle, vtable, read_buffer, write_buffer);
717 
718         s = io_read_encoded_string(interp, handle, vtable, read_buffer, encoding, length);
719         PARROT_ASSERT(s->strlen <= length);
720         Parrot_unblock_GC_move(interp);
721         return s;
722     }
723 }
724 
725 PARROT_EXPORT
726 PARROT_CANNOT_RETURN_NULL
727 PARROT_DEPRECATED
728 STRING *
Parrot_io_recv_handle(PARROT_INTERP,ARGMOD (PMC * pmc),size_t len)729 Parrot_io_recv_handle(PARROT_INTERP, ARGMOD(PMC *pmc), size_t len)
730 {
731     ASSERT_ARGS(Parrot_io_recv_handle)
732     return Parrot_io_read_s(interp, pmc, len);
733 }
734 
735 /*
736 
737 =item C<STRING * Parrot_io_readall_s(PARROT_INTERP, PMC *handle)>
738 
739 Read the remainder of text from the handle, returning all complete codepoints
740 in a C<STRING*>. Notice that some bytes which represent incomplete an
741 incomplete codepoint at the end of the input may be omitted.
742 
743 Notice that this routine may automatically allocate a read buffer for
744 multi-byte encodeded inputs.
745 
746 =cut
747 
748 */
749 
750 PARROT_EXPORT
751 PARROT_WARN_UNUSED_RESULT
752 PARROT_CANNOT_RETURN_NULL
753 STRING *
Parrot_io_readall_s(PARROT_INTERP,ARGMOD (PMC * handle))754 Parrot_io_readall_s(PARROT_INTERP, ARGMOD(PMC *handle))
755 {
756     ASSERT_ARGS(Parrot_io_readall_s)
757     const IO_VTABLE * vtable;
758     if (PMC_IS_NULL(handle))
759         Parrot_ex_throw_from_c_noargs(interp, EXCEPTION_PIO_ERROR,
760             "Attempt to read from null or invalid PMC");
761 
762     vtable = IO_GET_VTABLE(interp, handle);
763     io_verify_is_open_for(interp, handle, vtable, PIO_F_READ);
764 
765     {
766         /* TODO: Refactor this stuff out into helper methods to be less
767            confusing and verbose here. */
768         /* TODO: Do not automatically allocate a buffer for fixed8 encoded
769            strings. */
770         IO_BUFFER * const write_buffer = IO_GET_WRITE_BUFFER(interp, handle);
771         const STR_VTABLE * const encoding = io_get_encoding(interp, handle, vtable, PIO_F_READ);
772         size_t total_size = vtable->total_size(interp, handle);
773 
774         if (total_size == 0)
775             return Parrot_str_new_init(interp, "", 0, encoding, 0);
776 
777         if (total_size == PIO_UNKNOWN_SIZE) {
778             IO_BUFFER * const read_buffer = io_verify_has_read_buffer(interp, handle, vtable,
779                                                                       BUFFER_FLAGS_ANY);
780             size_t available_bytes = Parrot_io_buffer_fill(interp, read_buffer, handle, vtable);
781             STRING * const s = io_get_new_empty_string(interp, encoding, -1,
782                                                        PIO_STRING_BUFFER_MINSIZE);
783 
784             io_sync_buffers_for_read(interp, handle, vtable, read_buffer, write_buffer);
785             while (available_bytes > 0 && !Parrot_io_eof(interp, handle)) {
786                 io_read_chars_append_string(interp, s, handle, vtable, read_buffer,
787                                             available_bytes);
788                 available_bytes = Parrot_io_buffer_fill(interp, read_buffer, handle, vtable);
789             }
790             return s;
791         }
792         else {
793             size_t remaining_size = total_size - vtable->get_position(interp, handle);
794             IO_BUFFER * const read_buffer = IO_GET_READ_BUFFER(interp, handle);
795             STRING * const s = io_get_new_empty_string(interp, encoding, -1, remaining_size);
796 
797             io_sync_buffers_for_read(interp, handle, vtable, read_buffer, write_buffer);
798             if (remaining_size > 0 && !Parrot_io_eof(interp, handle))
799                 io_read_chars_append_string(interp, s, handle, vtable, read_buffer, remaining_size);
800             return s;
801         }
802     }
803 }
804 
805 /*
806 
807 =item C<PMC * Parrot_io_read_byte_buffer_pmc(PARROT_INTERP, PMC *handle, PMC
808 *buffer, size_t byte_length)>
809 
810 Read C<length> bytes from the C<handle> into the C<buffer> (ByteBuffer) PMC.
811 
812 =item C<INTVAL Parrot_io_write_byte_buffer_pmc(PARROT_INTERP, PMC * handle, PMC
813 *buffer, size_t byte_length)>
814 
815 Write C<length> bytes (or the total length of C<buffer>, whichever is smaller)
816 from C<buffer> to the C<handle>
817 
818 =cut
819 
820 */
821 
822 
823 PARROT_EXPORT
824 PARROT_CANNOT_RETURN_NULL
825 PMC *
Parrot_io_read_byte_buffer_pmc(PARROT_INTERP,ARGMOD (PMC * handle),ARGMOD_NULLOK (PMC * buffer),size_t byte_length)826 Parrot_io_read_byte_buffer_pmc(PARROT_INTERP, ARGMOD(PMC *handle),
827         ARGMOD_NULLOK(PMC *buffer), size_t byte_length)
828 {
829     ASSERT_ARGS(Parrot_io_read_byte_buffer_pmc)
830 
831     if (PMC_IS_NULL(handle))
832         Parrot_ex_throw_from_c_noargs(interp, EXCEPTION_PIO_ERROR,
833             "Attempt to read bytes from a null or invalid PMC");
834 
835     if (PMC_IS_NULL(buffer))
836         buffer = Parrot_pmc_new(interp, enum_class_ByteBuffer);
837 
838     if (!byte_length)
839         return buffer;
840 
841     {
842         const IO_VTABLE * const vtable = IO_GET_VTABLE(interp, handle);
843         IO_BUFFER * const read_buffer  = IO_GET_READ_BUFFER(interp, handle);
844         IO_BUFFER * const write_buffer = IO_GET_WRITE_BUFFER(interp, handle);
845         size_t bytes_read;
846         char * content;
847 
848         /* Prepare to read */
849         io_verify_is_open_for(interp, handle, vtable, PIO_F_READ);
850         io_sync_buffers_for_read(interp, handle, vtable, read_buffer, write_buffer);
851 
852         /* If the user has not specified a read size, we want to get data as
853            lazily as possible. If we have something in the buffer, read that
854            out. Otherwise, fill the buffer and use whatever we get. */
855         if (byte_length == PIO_READ_SIZE_ANY) {
856             const size_t available_bytes = BUFFER_USED_SIZE(read_buffer);
857             if (available_bytes >= read_buffer->encoding->max_bytes_per_codepoint)
858                 byte_length = available_bytes;
859             else
860                 byte_length = Parrot_io_buffer_fill(interp, read_buffer, handle, vtable);
861             if (byte_length <= 0)
862                 return buffer;
863         }
864 
865         VTABLE_set_integer_native(interp, buffer, byte_length);
866         content = (char *)VTABLE_get_pointer(interp, buffer);
867         bytes_read = Parrot_io_buffer_read_b(interp, read_buffer, handle, vtable, content,
868                                              byte_length);
869 
870         /* If we read less than we requested, re-size the buffer. If we got
871            no bytes, we're at EOF. If we got something, advance the handle to
872            account for whatever we read. */
873         if (bytes_read != byte_length)
874             VTABLE_set_integer_native(interp, buffer, bytes_read);
875         if (bytes_read == 0)
876             vtable->set_eof(interp, handle, 1);
877         vtable->adv_position(interp, handle, bytes_read);
878         return buffer;
879     }
880 }
881 
882 INTVAL
Parrot_io_write_byte_buffer_pmc(PARROT_INTERP,ARGMOD (PMC * handle),ARGMOD (PMC * buffer),size_t byte_length)883 Parrot_io_write_byte_buffer_pmc(PARROT_INTERP, ARGMOD(PMC * handle),
884         ARGMOD(PMC *buffer), size_t byte_length)
885 {
886     ASSERT_ARGS(Parrot_io_write_byte_buffer_pmc)
887 
888     if (PMC_IS_NULL(buffer))
889         Parrot_ex_throw_from_c_noargs(interp, EXCEPTION_PIO_ERROR,
890             "Attempt to read bytes from a null or invalid ByteBuffer");
891 
892     if (!byte_length)
893         return 0;
894 
895     {
896         char *content = (char *)VTABLE_get_pointer(interp, buffer);
897         size_t real_length = (size_t)VTABLE_elements(interp, buffer);
898 
899         if (real_length < byte_length)
900             byte_length = real_length;
901 
902         return Parrot_io_write_b(interp, handle, content, byte_length);
903     }
904 }
905 
906 /*
907 
908 =item C<STRING * Parrot_io_readline_s(PARROT_INTERP, PMC *handle, STRING *
909 terminator)>
910 
911 Return a new C<STRING*> holding the next line read from the file starting from
912 the current read position until the next instance of the C<terminator>
913 character or the end of the input. This function will not return incomplete
914 codepoints at the end of the string if enough data to complete the final
915 codepoint is not available to be read. Notice that this function may
916 automatically allocate a buffer for multi-byte encoded strings.
917 
918 =item C<STRING * Parrot_io_readline(PARROT_INTERP, PMC *handle)>
919 
920 Legacy wrapper for C<Parrot_io_readline_s>. Deprecated. Do not use.
921 
922 =cut
923 
924 */
925 
926 PARROT_EXPORT
927 PARROT_WARN_UNUSED_RESULT
928 PARROT_CANNOT_RETURN_NULL
929 PARROT_DEPRECATED
930 STRING *
Parrot_io_readline(PARROT_INTERP,ARGMOD (PMC * handle))931 Parrot_io_readline(PARROT_INTERP, ARGMOD(PMC *handle))
932 {
933     ASSERT_ARGS(Parrot_io_readline)
934 
935     STRING * terminator;
936     GETATTR_Handle_record_separator(interp, handle, terminator);
937 
938     return Parrot_io_readline_s(interp, handle, terminator);
939 }
940 
941 PARROT_EXPORT
942 PARROT_WARN_UNUSED_RESULT
943 PARROT_CANNOT_RETURN_NULL
944 STRING *
Parrot_io_readline_s(PARROT_INTERP,ARGMOD (PMC * handle),ARGIN (STRING * terminator))945 Parrot_io_readline_s(PARROT_INTERP, ARGMOD(PMC *handle), ARGIN(STRING * terminator))
946 {
947     ASSERT_ARGS(Parrot_io_readline_s)
948 
949     if (PMC_IS_NULL(handle))
950         Parrot_ex_throw_from_c_noargs(interp, EXCEPTION_PIO_ERROR,
951             "Attempt to read bytes from a null or invalid PMC");
952 
953     if (STRING_IS_NULL(terminator) || STRING_length(terminator) == 0)
954         terminator = CONST_STRING(interp, "\n");
955 
956     {
957         /* TODO: Try not to automatically allocate a read buffer for fixed8
958            strings. */
959         const IO_VTABLE * const vtable = IO_GET_VTABLE(interp, handle);
960         IO_BUFFER * read_buffer = IO_GET_READ_BUFFER(interp, handle);
961         IO_BUFFER * const write_buffer = IO_GET_WRITE_BUFFER(interp, handle);
962         size_t max_delimiter_byte_size = 0;
963 
964         io_sync_buffers_for_read(interp, handle, vtable, read_buffer, write_buffer);
965         io_verify_is_open_for(interp, handle, vtable, PIO_F_READ);
966 
967         if (read_buffer == NULL)
968             read_buffer = io_verify_has_read_buffer(interp, handle, vtable, BUFFER_SIZE_ANY);
969 
970         /* Because of the way buffering works, the terminator sequence may be,
971            at most, one character shorter than half the size of the buffer.
972            Most cases will use "\n" or "\r\n" or some permutation thereof, so
973            this isn't a big deal. */
974         max_delimiter_byte_size = (read_buffer->buffer_size / 2) -
975                                      STRING_max_bytes_per_codepoint(terminator);
976         if (terminator->bufused > max_delimiter_byte_size)
977             Parrot_ex_throw_from_c_args(interp, NULL, EXCEPTION_PIO_ERROR,
978                 "Readline terminator string must be smaller than %d bytes for this buffer");
979 
980         return io_readline_encoded_string(interp, handle, vtable, read_buffer, NULL, terminator);
981     }
982 }
983 
984 /*
985 
986 =item C<size_t Parrot_io_write_b(PARROT_INTERP, PMC *handle, const void *buffer,
987 size_t byte_length)>
988 
989 Writes C<len> bytes from C<*buffer> to C<*pmc>. This is for raw outputs and
990 does not take into account string encodings or other features. The handle
991 C<pmc> must be a valid handle type and must be opened for writing.
992 
993 If the handle has a buffer set up, the data may be written to the buffer and
994 not written out to the handle, depending on settings.
995 
996 =cut
997 
998 */
999 
1000 PARROT_EXPORT
1001 size_t
Parrot_io_write_b(PARROT_INTERP,ARGMOD (PMC * handle),ARGIN (const void * buffer),size_t byte_length)1002 Parrot_io_write_b(PARROT_INTERP, ARGMOD(PMC *handle), ARGIN(const void *buffer),
1003         size_t byte_length)
1004 {
1005     ASSERT_ARGS(Parrot_io_write_b)
1006 
1007     if (PMC_IS_NULL(handle))
1008         Parrot_ex_throw_from_c_noargs(interp, EXCEPTION_PIO_ERROR,
1009             "Attempt to write bytes to a null or invalid PMC");
1010 
1011     if (!byte_length)
1012         return 0;
1013 
1014     {
1015         const IO_VTABLE * const vtable = IO_GET_VTABLE(interp, handle);
1016         IO_BUFFER * const write_buffer = IO_GET_WRITE_BUFFER(interp, handle);
1017         IO_BUFFER * const read_buffer = IO_GET_READ_BUFFER(interp, handle);
1018         size_t bytes_written;
1019 
1020         io_verify_is_open_for(interp, handle, vtable, PIO_F_WRITE);
1021         io_sync_buffers_for_write(interp, handle, vtable, read_buffer, write_buffer);
1022         bytes_written = Parrot_io_buffer_write_b(interp, write_buffer, handle, vtable,
1023                                                  (char *)PTR2INTVAL(buffer), byte_length);
1024         vtable->adv_position(interp, handle, bytes_written);
1025 
1026         /* If we are writing to a r/w handle, advance the pointer in the
1027            associated read-buffer since we're overwriting those characters. */
1028         Parrot_io_buffer_advance_position(interp, read_buffer, bytes_written);
1029         return bytes_written;
1030     }
1031 }
1032 
1033 /*
1034 
1035 =item C<INTVAL Parrot_io_write_s(PARROT_INTERP, PMC *handle, const STRING *
1036 const s)>
1037 
1038 Write Parrot C<STRING*> C<s> to the handle C<handle>. C<s> may be re-encoded
1039 to match the specified encoding for C<handle>. If the C<handle> has a write
1040 buffer set up, the data may be written to the buffer only and not written to
1041 the C<handle>.
1042 
1043 Returns the total number of bytes written.
1044 
1045 =cut
1046 
1047 */
1048 
1049 
1050 PARROT_EXPORT
1051 INTVAL
Parrot_io_write_s(PARROT_INTERP,ARGMOD (PMC * handle),ARGIN (const STRING * const s))1052 Parrot_io_write_s(PARROT_INTERP, ARGMOD(PMC *handle), ARGIN(const STRING * const s))
1053 {
1054     ASSERT_ARGS(Parrot_io_write_s)
1055 
1056     if (PMC_IS_NULL(handle))
1057         Parrot_ex_throw_from_c_noargs(interp, EXCEPTION_PIO_ERROR,
1058             "Attempt to write a string to a null or invalid PMC");
1059 
1060     if (STRING_IS_NULL(s) || STRING_length(s) == 0)
1061         return 0;
1062 
1063     {
1064         const IO_VTABLE * const vtable = IO_GET_VTABLE(interp, handle);
1065         IO_BUFFER * const write_buffer = IO_GET_WRITE_BUFFER(interp, handle);
1066         IO_BUFFER * const read_buffer  = IO_GET_READ_BUFFER(interp, handle);
1067         STRING *out_s;
1068         size_t bytes_written;
1069 
1070         io_verify_is_open_for(interp, handle, vtable, PIO_F_WRITE);
1071 
1072         Parrot_block_GC_sweep(interp); /* Our local string may not move away. GH #1196 */
1073         io_sync_buffers_for_write(interp, handle, vtable, read_buffer, write_buffer);
1074         out_s = io_verify_string_encoding(interp, handle, vtable, s, PIO_F_WRITE);
1075         bytes_written = Parrot_io_buffer_write_b(interp, write_buffer, handle,
1076                                     vtable, out_s->strstart, out_s->bufused);
1077         vtable->adv_position(interp, handle, bytes_written);
1078         Parrot_unblock_GC_sweep(interp);
1079 
1080         /* If we are writing to a r/w handle, advance the pointer in the
1081            associated read-buffer since we're overwriting those characters. */
1082         Parrot_io_buffer_advance_position(interp, read_buffer, bytes_written);
1083         return bytes_written;
1084     }
1085 }
1086 
1087 /*
1088 
1089 =item C<PIOOFF_T Parrot_io_seek(PARROT_INTERP, PMC *handle, PIOOFF_T offset,
1090 INTVAL w)>
1091 
1092 Moves the read/write position of C<*pmc> to offset C<bytes> from the
1093 position indicated by C<w>. Typically C<w> will be C<0> for the start of
1094 the file, C<1> for the current position, and C<2> for the end. Notice that
1095 this affects Parrot's in-memory file position and not necessarily the on-disk
1096 file position according to the operating system (or whatever the equivalent
1097 operation is for the given type of C<handle>).
1098 
1099 =item C<PIOOFF_T Parrot_io_seek_handle(PARROT_INTERP, PMC *handle, PIOOFF_T
1100 offset, INTVAL w)>
1101 
1102 Legacy wrapper for Parrot_io_seek. Deprecated. Do not use.
1103 
1104 =cut
1105 
1106 */
1107 
1108 PARROT_EXPORT
1109 PARROT_WARN_UNUSED_RESULT
1110 PIOOFF_T
Parrot_io_seek_handle(PARROT_INTERP,ARGMOD (PMC * handle),PIOOFF_T offset,INTVAL w)1111 Parrot_io_seek_handle(PARROT_INTERP, ARGMOD(PMC *handle), PIOOFF_T offset, INTVAL w)
1112 {
1113     ASSERT_ARGS(Parrot_io_seek_handle)
1114     return Parrot_io_seek(interp, handle, offset, w);
1115 }
1116 
1117 PARROT_EXPORT
1118 PARROT_WARN_UNUSED_RESULT
1119 PIOOFF_T
Parrot_io_seek(PARROT_INTERP,ARGMOD (PMC * handle),PIOOFF_T offset,INTVAL w)1120 Parrot_io_seek(PARROT_INTERP, ARGMOD(PMC *handle), PIOOFF_T offset, INTVAL w)
1121 {
1122     ASSERT_ARGS(Parrot_io_seek)
1123     if (Parrot_io_is_closed(interp, handle))
1124         return -1;
1125 
1126     {
1127         const IO_VTABLE * const vtable = IO_GET_VTABLE(interp, handle);
1128         IO_BUFFER * const read_buffer = IO_GET_READ_BUFFER(interp, handle);
1129         IO_BUFFER * const write_buffer = IO_GET_WRITE_BUFFER(interp, handle);
1130 
1131         /* Because of buffering we cannot really seek from the current file
1132            position. Take the current file position and turn it into an
1133            offset relative to the beginning of the file. */
1134         if (w == SEEK_CUR) {
1135             const PIOOFF_T file_pos = vtable->get_position(interp, handle);
1136             offset += file_pos;
1137             w  = SEEK_SET;
1138         }
1139 
1140         /* If we have a write buffer, flush that out to disk before we attempt
1141            to do any seek operation. We need the data there before we can
1142            seek. */
1143         if (write_buffer)
1144             Parrot_io_buffer_flush(interp, write_buffer, handle, vtable);
1145 
1146         if (read_buffer && w != SEEK_END) {
1147             const PIOOFF_T new_offset = Parrot_io_buffer_seek(interp, read_buffer,
1148                                                 handle, vtable, offset, w);
1149             vtable->set_position(interp, handle, new_offset);
1150             return new_offset;
1151         }
1152 
1153         return vtable->seek(interp, handle, offset, w);
1154     }
1155 }
1156 
1157 /*
1158 
1159 =item C<PIOOFF_T Parrot_io_tell(PARROT_INTERP, PMC *handle)>
1160 
1161 Returns the current read/write position of C<*pmc>. Notice that this position
1162 information may be calculated depending on the presence of buffers and other
1163 factors and may not accurately represent the on-disk position according to the
1164 operating system (or the equivalent for other types).
1165 
1166 =item C<PIOOFF_T Parrot_io_tell_handle(PARROT_INTERP, PMC *handle)>
1167 
1168 Legacy wrapper for Parrot_io_tell. Deprecated. Do not use.
1169 
1170 =cut
1171 
1172 */
1173 
1174 PARROT_EXPORT
1175 PARROT_WARN_UNUSED_RESULT
1176 PIOOFF_T
Parrot_io_tell_handle(PARROT_INTERP,ARGMOD (PMC * handle))1177 Parrot_io_tell_handle(PARROT_INTERP, ARGMOD(PMC *handle))
1178 {
1179     ASSERT_ARGS(Parrot_io_tell_handle)
1180     return Parrot_io_tell(interp, handle);
1181 }
1182 
1183 PARROT_EXPORT
1184 PARROT_WARN_UNUSED_RESULT
1185 PIOOFF_T
Parrot_io_tell(PARROT_INTERP,ARGMOD (PMC * handle))1186 Parrot_io_tell(PARROT_INTERP, ARGMOD(PMC *handle))
1187 {
1188     ASSERT_ARGS(Parrot_io_tell)
1189     if (Parrot_io_is_closed(interp, handle))
1190         return -1;
1191     {
1192         const IO_VTABLE * const vtable = IO_GET_VTABLE(interp, handle);
1193         IO_BUFFER * const read_buffer = IO_GET_READ_BUFFER(interp, handle);
1194         IO_BUFFER * const write_buffer = IO_GET_WRITE_BUFFER(interp, handle);
1195 
1196         if (write_buffer)
1197             Parrot_io_buffer_flush(interp, write_buffer, handle, vtable);
1198 
1199         return Parrot_io_buffer_tell(interp, read_buffer, handle, vtable);
1200     }
1201 }
1202 
1203 /*
1204 
1205 =item C<STRING * Parrot_io_peek(PARROT_INTERP, PMC *handle)>
1206 
1207 Retrieve the next byte in the stream without modifying the stream. May peek
1208 from the read buffer and may configure a read buffer if one does not already
1209 exist.
1210 
1211 =cut
1212 
1213 */
1214 
1215 PARROT_EXPORT
1216 PARROT_WARN_UNUSED_RESULT
1217 PARROT_CANNOT_RETURN_NULL
1218 STRING *
Parrot_io_peek(PARROT_INTERP,ARGMOD (PMC * handle))1219 Parrot_io_peek(PARROT_INTERP, ARGMOD(PMC *handle))
1220 {
1221     ASSERT_ARGS(Parrot_io_peek)
1222 
1223     if (PMC_IS_NULL(handle) || Parrot_io_is_closed(interp, handle))
1224         return STRINGNULL;
1225     {
1226         const IO_VTABLE * const vtable = IO_GET_VTABLE(interp, handle);
1227         IO_BUFFER * const read_buffer = IO_GET_READ_BUFFER(interp, handle);
1228         const INTVAL c = Parrot_io_buffer_peek(interp, read_buffer, handle, vtable);
1229 
1230         if (c == -1)
1231             return STRINGNULL;
1232         else
1233             return Parrot_str_chr(interp, c);
1234     }
1235 }
1236 
1237 /*
1238 
1239 =item C<INTVAL Parrot_io_eof(PARROT_INTERP, const PMC * const handle)>
1240 
1241 Returns C<1> if the C<handle> is at end-of-file (or the type-specific
1242 equivalent). Returns C<1> if the handle is null, closed, or otherwise not
1243 accessible. Notice that this tells the position of Parrot's in-memory read
1244 cursor and not the on-disk position according to the operating system. If the
1245 handle has been exhausted but unread data remains in the read buffer, the
1246 handle is not considered to be at EOF.
1247 
1248 =cut
1249 
1250 */
1251 
1252 PARROT_EXPORT
1253 PARROT_WARN_UNUSED_RESULT
1254 INTVAL
Parrot_io_eof(PARROT_INTERP,ARGIN (const PMC * const handle))1255 Parrot_io_eof(PARROT_INTERP, ARGIN(const PMC * const handle))
1256 {
1257     ASSERT_ARGS(Parrot_io_eof)
1258     /* io could be null here, but rather than return a negative error
1259      * we just fake EOF since eof test is usually in a boolean context.
1260      */
1261     if (PMC_IS_NULL(handle))
1262         return 1;
1263     if (Parrot_io_is_closed(interp, (PMC*)handle))
1264         return 1;
1265     {
1266         IO_BUFFER * const buffer = IO_GET_READ_BUFFER(interp, (PMC*)handle);
1267         const IO_VTABLE * const vtable = IO_GET_VTABLE(interp, (PMC*)handle);
1268         if (buffer)
1269             return BUFFER_IS_EMPTY(buffer) && vtable->is_eof(interp, handle);
1270         return vtable->is_eof(interp, handle);
1271     }
1272 }
1273 
1274 /*
1275 
1276 =item C<INTVAL Parrot_io_puts(PARROT_INTERP, const PMC * const pmc, const char
1277 *s)>
1278 
1279 Legacy wrapper for C<Parrot_io_write_b>. Deprecated. Do not use
1280 
1281 =cut
1282 
1283 */
1284 
1285 PARROT_EXPORT
1286 PARROT_DEPRECATED
1287 INTVAL
Parrot_io_puts(PARROT_INTERP,ARGIN (const PMC * const pmc),ARGIN (const char * s))1288 Parrot_io_puts(PARROT_INTERP, ARGIN(const PMC * const pmc), ARGIN(const char *s))
1289 {
1290     ASSERT_ARGS(Parrot_io_puts)
1291     return Parrot_io_write_b(interp, (PMC*)pmc, s, strlen(s));
1292 }
1293 
1294 /*
1295 
1296 =item C<INTVAL Parrot_io_putps(PARROT_INTERP, const PMC * const pmc, const
1297 STRING * const s)>
1298 
1299 Legacy Wrapper for C<Parrot_io_write_s>. Deprecated. Do not use.
1300 
1301 =cut
1302 
1303 */
1304 
1305 PARROT_EXPORT
1306 PARROT_DEPRECATED
1307 INTVAL
Parrot_io_putps(PARROT_INTERP,ARGIN (const PMC * const pmc),ARGIN (const STRING * const s))1308 Parrot_io_putps(PARROT_INTERP, ARGIN(const PMC * const pmc), ARGIN(const STRING * const s))
1309 {
1310     ASSERT_ARGS(Parrot_io_putps)
1311     return Parrot_io_write_s(interp, (PMC*)pmc, s);
1312 }
1313 
1314 /*
1315 
1316 =item C<INTVAL Parrot_io_fprintf(PARROT_INTERP, const PMC * const pmc,
1317 ARGIN_FORMAT(const char *s), ...)>
1318 
1319 Writes a C string format with varargs to C<*pmc>. Uses C<Parrot_io_write_s> to
1320 write the formatted string, and is subject to all the limitations thereof.
1321 
1322 =cut
1323 
1324 */
1325 
1326 PARROT_EXPORT
1327 PARROT_IGNORABLE_RESULT
1328 INTVAL
Parrot_io_fprintf(PARROT_INTERP,ARGIN (const PMC * const pmc),ARGIN_FORMAT (const char * s),...)1329 Parrot_io_fprintf(PARROT_INTERP, ARGIN(const PMC * const pmc), ARGIN_FORMAT(const char *s), ...)
1330 {
1331     ASSERT_ARGS(Parrot_io_fprintf)
1332     va_list args;
1333     INTVAL ret;
1334 
1335     va_start(args, s);
1336     {
1337         STRING * const str = Parrot_vsprintf_c(interp, s, args);
1338         ret = Parrot_io_write_s(interp, (PMC*)pmc, str);
1339     }
1340     va_end(args);
1341 
1342     return ret;
1343 }
1344 
1345 /*
1346 
1347 =item C<INTVAL Parrot_io_pprintf(PARROT_INTERP, const PIOHANDLE os_handle,
1348 ARGIN_FORMAT(const char *s), ...)>
1349 
1350 Writes a C string format with varargs to PIOHANDLE C<os_handle>. Writes
1351 directly to the givem C<os_handle> without any intermediate buffering or other
1352 logic common to Parrot Handle PMCs.
1353 
1354 =cut
1355 
1356 */
1357 
1358 PARROT_EXPORT
1359 PARROT_IGNORABLE_RESULT
1360 INTVAL
Parrot_io_pprintf(PARROT_INTERP,const PIOHANDLE os_handle,ARGIN_FORMAT (const char * s),...)1361 Parrot_io_pprintf(PARROT_INTERP, const PIOHANDLE os_handle, ARGIN_FORMAT(const char *s), ...)
1362 {
1363     ASSERT_ARGS(Parrot_io_pprintf)
1364     va_list  args;
1365     STRING  *str;
1366 
1367     va_start(args, s);
1368     str = Parrot_vsprintf_c(interp, s, args);
1369     va_end(args);
1370 
1371     return Parrot_io_internal_write(interp, os_handle, str->strstart, str->bufused);
1372 }
1373 
1374 /*
1375 
1376 =item C<INTVAL Parrot_io_printf(PARROT_INTERP, ARGIN_FORMAT(const char *s),
1377 ...)>
1378 
1379 Writes a C string format with varargs to C<stdout>. This routine uses
1380 Parrot_io_write_s to perform the actual write, and is therefore subject to
1381 all the same semantics and limitations.
1382 
1383 =cut
1384 
1385 */
1386 
1387 PARROT_EXPORT
1388 PARROT_IGNORABLE_RESULT
1389 INTVAL
Parrot_io_printf(PARROT_INTERP,ARGIN_FORMAT (const char * s),...)1390 Parrot_io_printf(PARROT_INTERP, ARGIN_FORMAT(const char *s), ...)
1391 {
1392     ASSERT_ARGS(Parrot_io_printf)
1393     va_list args;
1394     INTVAL ret;
1395 
1396     va_start(args, s);
1397 
1398     if (interp) {
1399         STRING * const str = Parrot_vsprintf_c(interp, s, args);
1400         ret = Parrot_io_write_s(interp, _PIO_STDOUT(interp), str);
1401     }
1402     else
1403         ret = vfprintf(stdout, s, args);
1404 
1405     va_end(args);
1406 
1407     return ret;
1408 }
1409 
1410 /*
1411 
1412 =item C<INTVAL Parrot_io_eprintf(PARROT_INTERP, const char *s, ...)>
1413 
1414 Writes a C string format with varargs to C<stderr>. This routine uses
1415 C<Parrot_io_write_s> to perform the actual write, and is therefore subject to
1416 all the same semantics and limitations.
1417 
1418 =cut
1419 
1420 Note: We cannot use ARGIN_FORMAT here as it is used with non-standard P%vd formats.
1421 
1422 */
1423 
1424 PARROT_EXPORT
1425 PARROT_IGNORABLE_RESULT
1426 INTVAL
Parrot_io_eprintf(NULLOK (PARROT_INTERP),ARGIN (const char * s),...)1427 Parrot_io_eprintf(NULLOK(PARROT_INTERP), ARGIN(const char *s), ...)
1428 {
1429     ASSERT_ARGS(Parrot_io_eprintf)
1430     va_list args;
1431     INTVAL ret;
1432 
1433     va_start(args, s);
1434 
1435     if (interp) {
1436         STRING * const str = Parrot_vsprintf_c(interp, s, args);
1437         ret = Parrot_io_write_s(interp, _PIO_STDERR(interp), str);
1438     }
1439     else
1440         ret = vfprintf(stderr, s, args);
1441 
1442     va_end(args);
1443 
1444     return ret;
1445 }
1446 
1447 /*
1448 
1449 =item C<PIOHANDLE Parrot_io_getfd(PARROT_INTERP, PMC *pmc)>
1450 
1451 This is a legacy wrapper for Parrot_io_get_os_handle. Deprecated. Do not use.
1452 
1453 =cut
1454 
1455 */
1456 
1457 PARROT_EXPORT
1458 PARROT_WARN_UNUSED_RESULT
1459 PARROT_DEPRECATED
1460 PIOHANDLE
Parrot_io_getfd(PARROT_INTERP,ARGIN (PMC * pmc))1461 Parrot_io_getfd(PARROT_INTERP, ARGIN(PMC *pmc))
1462 {
1463     ASSERT_ARGS(Parrot_io_getfd)
1464     return Parrot_io_get_os_handle(interp, pmc);
1465 }
1466 
1467 /*
1468 
1469 =item C<INTVAL Parrot_io_is_tty_handle(PARROT_INTERP, PMC *pmc)>
1470 
1471 Returns a boolean value indicating whether C<*pmc> is a console/tty. Returns
1472 C<0> if the C<pmc> is null or closed.
1473 
1474 =cut
1475 
1476 */
1477 
1478 PARROT_EXPORT
1479 PARROT_WARN_UNUSED_RESULT
1480 INTVAL
Parrot_io_is_tty_handle(PARROT_INTERP,ARGIN (PMC * pmc))1481 Parrot_io_is_tty_handle(PARROT_INTERP, ARGIN(PMC *pmc))
1482 {
1483     ASSERT_ARGS(Parrot_io_is_tty_handle)
1484     if (Parrot_io_is_closed(interp, pmc))
1485         return 0;
1486 
1487     return (Parrot_io_get_flags(interp, pmc) & PIO_F_CONSOLE) ? 1 : 0;
1488 }
1489 
1490 /*
1491 
1492 =item C<INTVAL Parrot_io_is_async(PARROT_INTERP, PMC *pmc)>
1493 
1494 Returns 0 for now. Parrot does not support async operations.
1495 
1496 =cut
1497 
1498 */
1499 
1500 PARROT_EXPORT
1501 PARROT_WARN_UNUSED_RESULT
1502 INTVAL
Parrot_io_is_async(PARROT_INTERP,ARGMOD (PMC * pmc))1503 Parrot_io_is_async(PARROT_INTERP, ARGMOD(PMC *pmc))
1504 {
1505     ASSERT_ARGS(Parrot_io_is_async)
1506     if (Parrot_io_is_closed(interp, pmc))
1507         return 0;
1508 
1509 /* return (Parrot_io_get_flags(interp, pmc) & PIO_F_ASYNC) ? 1 : 0; */
1510     return 0;
1511 }
1512 
1513 /*
1514 
1515 =back
1516 
1517 =head2 C<Parrot_io_STD*> Functions
1518 
1519 =over 4
1520 
1521 =item C<PMC * Parrot_io_STDIN(PARROT_INTERP)>
1522 
1523 Returns the C<FileHandle> PMC for C<stdin>.
1524 
1525 =cut
1526 
1527 */
1528 
1529 PARROT_EXPORT
1530 PARROT_WARN_UNUSED_RESULT
1531 PARROT_CANNOT_RETURN_NULL
1532 PMC *
Parrot_io_STDIN(PARROT_INTERP)1533 Parrot_io_STDIN(PARROT_INTERP)
1534 {
1535     ASSERT_ARGS(Parrot_io_STDIN)
1536     return _PIO_STDIN(interp);
1537 }
1538 
1539 /*
1540 
1541 =item C<PMC * Parrot_io_STDOUT(PARROT_INTERP)>
1542 
1543 Returns the C<FileHandle> PMC for C<stdout>.
1544 
1545 =cut
1546 
1547 */
1548 
1549 PARROT_EXPORT
1550 PARROT_WARN_UNUSED_RESULT
1551 PARROT_CANNOT_RETURN_NULL
1552 PMC *
Parrot_io_STDOUT(PARROT_INTERP)1553 Parrot_io_STDOUT(PARROT_INTERP)
1554 {
1555     ASSERT_ARGS(Parrot_io_STDOUT)
1556     return _PIO_STDOUT(interp);
1557 }
1558 
1559 /*
1560 
1561 =item C<PMC * Parrot_io_STDERR(PARROT_INTERP)>
1562 
1563 Returns the C<FileHandle> PMC for C<stderr>.
1564 
1565 =cut
1566 
1567 */
1568 
1569 PARROT_EXPORT
1570 PARROT_WARN_UNUSED_RESULT
1571 PARROT_CANNOT_RETURN_NULL
1572 PMC *
Parrot_io_STDERR(PARROT_INTERP)1573 Parrot_io_STDERR(PARROT_INTERP)
1574 {
1575     ASSERT_ARGS(Parrot_io_STDERR)
1576     return _PIO_STDERR(interp);
1577 }
1578 
1579 /*
1580 
1581 =item C<PIOHANDLE Parrot_io_get_standard_piohandle(PARROT_INTERP, INTVAL idx)>
1582 
1583 Get the raw PIOHANDLE for one of the standard streams. Notice that this will FAIL in a bad way if
1584 the standard stream has been overridden with a handle type that isn't backed by a PIOHANDLE
1585 (StringHandle, etc).
1586 
1587 This function is a temporary stopgap solution and SHOULD NOT be used where possible. Instead, use
1588 the handle PMCs and functions on those directly instead of attempting lower-level accesses on the
1589 PIOHANDLE directly.
1590 
1591 =cut
1592 
1593 */
1594 
1595 PARROT_WARN_UNUSED_RESULT
1596 PIOHANDLE
Parrot_io_get_standard_piohandle(PARROT_INTERP,INTVAL idx)1597 Parrot_io_get_standard_piohandle(PARROT_INTERP, INTVAL idx)
1598 {
1599     ASSERT_ARGS(Parrot_io_get_standard_piohandle)
1600     PMC * handle_pmc;
1601     switch (idx) {
1602         case PIO_STDIN_FILENO:
1603             handle_pmc = _PIO_STDIN(interp);
1604             break;
1605         case PIO_STDOUT_FILENO:
1606             handle_pmc = _PIO_STDOUT(interp);
1607             break;
1608         case PIO_STDERR_FILENO:
1609             handle_pmc = _PIO_STDERR(interp);
1610             break;
1611         default:
1612             Parrot_ex_throw_from_c_args(interp, NULL, EXCEPTION_PIO_ERROR,
1613                 "Unknown standard handle %d", idx);
1614     }
1615 
1616     {
1617         const IO_VTABLE * const vtable = IO_GET_VTABLE(interp, handle_pmc);
1618         return vtable->get_piohandle(interp, handle_pmc);
1619     }
1620 }
1621 
1622 /*
1623 
1624 =back
1625 
1626 =head2 Offset Functions
1627 
1628 These are used to create offsets for the C<seek> op.
1629 
1630 =over 4
1631 
1632 =item C<PIOOFF_T Parrot_io_make_offset(INTVAL offset)>
1633 
1634 Returns C<offset>.
1635 
1636 =cut
1637 
1638 */
1639 
1640 PARROT_EXPORT
1641 PARROT_WARN_UNUSED_RESULT
1642 PIOOFF_T
Parrot_io_make_offset(INTVAL offset)1643 Parrot_io_make_offset(INTVAL offset)
1644 {
1645     ASSERT_ARGS(Parrot_io_make_offset)
1646     return offset;
1647 }
1648 
1649 /*
1650 
1651 =item C<PIOOFF_T Parrot_io_make_offset32(INTVAL hi, INTVAL lo)>
1652 
1653 C<hi> is shifted 32 bytes to the left and C<or>ed together with C<lo>.
1654 This allows 64-bit seeks with only 32-bit C<INTVALS>.
1655 
1656 =cut
1657 
1658 */
1659 
1660 PARROT_EXPORT
1661 PARROT_WARN_UNUSED_RESULT
1662 PIOOFF_T
Parrot_io_make_offset32(INTVAL hi,INTVAL lo)1663 Parrot_io_make_offset32(INTVAL hi, INTVAL lo)
1664 {
1665     ASSERT_ARGS(Parrot_io_make_offset32)
1666     return ((PIOOFF_T)hi << 31) | lo;
1667 }
1668 
1669 /*
1670 
1671 =item C<PIOOFF_T Parrot_io_make_offset_pmc(PARROT_INTERP, PMC *pmc)>
1672 
1673 Returns the return value of the C<get_integer> vtable on C<*pmc>.
1674 
1675 =cut
1676 
1677 */
1678 
1679 PARROT_WARN_UNUSED_RESULT
1680 PIOOFF_T
Parrot_io_make_offset_pmc(PARROT_INTERP,ARGMOD (PMC * pmc))1681 Parrot_io_make_offset_pmc(PARROT_INTERP, ARGMOD(PMC *pmc))
1682 {
1683     ASSERT_ARGS(Parrot_io_make_offset_pmc)
1684     /* TODO: This seems worthless. Kill it if not needed. */
1685     return VTABLE_get_integer(interp, pmc);
1686 }
1687 
1688 /*
1689 
1690 =item C<INTVAL Parrot_io_poll(PARROT_INTERP, PMC *pmc, INTVAL which, INTVAL sec,
1691 INTVAL usec)>
1692 
1693 Polls C<*pmc> for the events in C<which> every C<sec> seconds + C<usec>
1694 microseconds.
1695 
1696 =cut
1697 
1698 */
1699 
1700 PARROT_EXPORT
1701 INTVAL
Parrot_io_poll(PARROT_INTERP,ARGMOD (PMC * pmc),INTVAL which,INTVAL sec,INTVAL usec)1702 Parrot_io_poll(PARROT_INTERP, ARGMOD(PMC *pmc), INTVAL which, INTVAL sec, INTVAL usec)
1703 {
1704     ASSERT_ARGS(Parrot_io_poll)
1705     /* TODO: Can we move this to the IO_VTABLE and make it usable for all
1706        types? */
1707     Parrot_Socket_attributes *io = PARROT_SOCKET(pmc);
1708 
1709     if (Parrot_io_is_closed(interp, pmc))
1710         Parrot_ex_throw_from_c_noargs(interp, EXCEPTION_PIO_ERROR,
1711                 "Can't poll closed socket");
1712 
1713     return Parrot_io_internal_poll(interp, io->os_handle, which, sec, usec);
1714 }
1715 
1716 /*
1717 
1718 =item C<void Parrot_io_socket_connect(PARROT_INTERP, PMC *pmc, PMC *address)>
1719 
1720 Connects Socket C<pmc> to the given C<address>. Notice that this operation is
1721 only valid for Sockets. Throws an exception if the socket is closed or if a
1722 valid address is not provided.
1723 
1724 =cut
1725 
1726 */
1727 
1728 PARROT_EXPORT
1729 void
Parrot_io_socket_connect(PARROT_INTERP,ARGMOD (PMC * pmc),ARGMOD (PMC * address))1730 Parrot_io_socket_connect(PARROT_INTERP, ARGMOD(PMC *pmc), ARGMOD(PMC *address))
1731 {
1732     ASSERT_ARGS(Parrot_io_socket_connect)
1733     Parrot_Socket_attributes * const io = PARROT_SOCKET(pmc);
1734     int i;
1735 
1736     /* TODO: Move most of this logic to src/io/socket.c */
1737 
1738     if (Parrot_io_is_closed(interp, pmc))
1739         Parrot_ex_throw_from_c_noargs(interp, EXCEPTION_PIO_ERROR,
1740                 "Can't connect closed socket");
1741     if (PMC_IS_NULL(address))
1742         Parrot_ex_throw_from_c_noargs(interp, EXCEPTION_PIO_ERROR,
1743                 "Address is null");
1744 
1745     /* Iterate over all addresses if an array is passed */
1746     if (address->vtable->base_type != enum_class_Sockaddr) {
1747         INTVAL len = VTABLE_elements(interp, address);
1748 
1749         for (i = 0; i < len; ++i) {
1750             PMC *sa = VTABLE_get_pmc_keyed_int(interp, address, i);
1751             Parrot_Sockaddr_attributes * const sa_data = PARROT_SOCKADDR(sa);
1752 
1753             if (!Parrot_io_internal_addr_match(interp, sa, io->family, io->type,
1754                     io->protocol))
1755                 continue;
1756 
1757             io->remote = sa;
1758 
1759             Parrot_io_internal_connect(interp, io->os_handle, sa_data->pointer,
1760                     sa_data->len);
1761 
1762             return;
1763         }
1764 
1765         Parrot_ex_throw_from_c_args(interp, NULL, EXCEPTION_PIO_ERROR,
1766                 "No address found for family %d, type %d, proto %d",
1767                 io->family, io->type, io->protocol);
1768     }
1769 
1770     io->remote = address;
1771 
1772     Parrot_io_internal_connect(interp, io->os_handle,
1773             VTABLE_get_pointer(interp, address),
1774             VTABLE_get_integer(interp, address));
1775 }
1776 
1777 /*
1778 
1779 =item C<void Parrot_io_socket_bind(PARROT_INTERP, PMC *pmc, PMC *address)>
1780 
1781 Binds Socket C<*pmc>'s socket to the local address and port specified by
1782 C<*address>. Throws an exception if the Socket is closed or if C<address> is
1783 not valid. This operation only works for Sockets.
1784 
1785 =cut
1786 
1787 */
1788 
1789 PARROT_EXPORT
1790 void
Parrot_io_socket_bind(PARROT_INTERP,ARGMOD (PMC * pmc),ARGMOD (PMC * address))1791 Parrot_io_socket_bind(PARROT_INTERP, ARGMOD(PMC *pmc), ARGMOD(PMC *address))
1792 {
1793     ASSERT_ARGS(Parrot_io_socket_bind)
1794     Parrot_Socket_attributes * const io = PARROT_SOCKET(pmc);
1795     int i;
1796 
1797     /* TODO: Move most of this logic to src/io/socket.c */
1798 
1799     if (Parrot_io_is_closed(interp, pmc))
1800         Parrot_ex_throw_from_c_noargs(interp, EXCEPTION_PIO_ERROR,
1801                 "Can't bind closed socket");
1802     if (PMC_IS_NULL(address))
1803         Parrot_ex_throw_from_c_noargs(interp, EXCEPTION_PIO_ERROR,
1804                 "Address is null");
1805 
1806     /* Iterate over all addresses if an array is passed */
1807     if (address->vtable->base_type != enum_class_Sockaddr) {
1808         INTVAL len = VTABLE_elements(interp, address);
1809 
1810         for (i = 0; i < len; ++i) {
1811             PMC *sa = VTABLE_get_pmc_keyed_int(interp, address, i);
1812             Parrot_Sockaddr_attributes * const sa_data = PARROT_SOCKADDR(sa);
1813 
1814             if (!Parrot_io_internal_addr_match(interp, sa, io->family, io->type,
1815                     io->protocol))
1816                 continue;
1817 
1818             io->local = sa;
1819 
1820             Parrot_io_internal_bind(interp, io->os_handle, sa_data->pointer,
1821                     sa_data->len);
1822 
1823             return;
1824         }
1825 
1826         Parrot_ex_throw_from_c_args(interp, NULL, EXCEPTION_PIO_ERROR,
1827                 "No address found for family %d, type %d, proto %d",
1828                 io->family, io->type, io->protocol);
1829     }
1830 
1831     io->local = address;
1832 
1833     Parrot_io_internal_bind(interp, io->os_handle,
1834             VTABLE_get_pointer(interp, address),
1835             VTABLE_get_integer(interp, address));
1836 }
1837 
1838 /*
1839 
1840 =item C<void Parrot_io_socket_listen(PARROT_INTERP, PMC *pmc, INTVAL backlog)>
1841 
1842 Listens for new connections on socket C<*pmc>. Throws an exception if C<pmc>
1843 is closed. Notice that this operation only works for Sockets.
1844 
1845 =cut
1846 
1847 */
1848 
1849 PARROT_EXPORT
1850 void
Parrot_io_socket_listen(PARROT_INTERP,ARGMOD (PMC * pmc),INTVAL backlog)1851 Parrot_io_socket_listen(PARROT_INTERP, ARGMOD(PMC *pmc), INTVAL backlog)
1852 {
1853     ASSERT_ARGS(Parrot_io_socket_listen)
1854     const Parrot_Socket_attributes * const io = PARROT_SOCKET(pmc);
1855 
1856     if (Parrot_io_is_closed(interp, pmc))
1857         Parrot_ex_throw_from_c_noargs(interp, EXCEPTION_PIO_ERROR,
1858                 "Can't listen on closed socket");
1859 
1860     Parrot_io_internal_listen(interp, io->os_handle, backlog);
1861 }
1862 
1863 /*
1864 
1865 =item C<PMC * Parrot_io_socket_accept(PARROT_INTERP, PMC *pmc)>
1866 
1867 Accepts a new connection and returns a newly created C<ParrotIO> socket.
1868 Returns C<NULL> on failure.
1869 
1870 =cut
1871 
1872 */
1873 
1874 PARROT_EXPORT
1875 PARROT_WARN_UNUSED_RESULT
1876 PARROT_CANNOT_RETURN_NULL
1877 PMC *
Parrot_io_socket_accept(PARROT_INTERP,ARGMOD (PMC * pmc))1878 Parrot_io_socket_accept(PARROT_INTERP, ARGMOD(PMC *pmc))
1879 {
1880     ASSERT_ARGS(Parrot_io_socket_accept)
1881 
1882     /* TODO: Move most of this logic to src/io/socket.c */
1883 
1884     Parrot_Socket_attributes *io = PARROT_SOCKET(pmc);
1885     Parrot_Socket_attributes *new_io;
1886     PMC       *new_pmc;
1887 
1888     if (Parrot_io_is_closed(interp, pmc))
1889         return PMCNULL;
1890 
1891     new_pmc = io_get_new_socket(interp);
1892     new_io  = PARROT_SOCKET(new_pmc);
1893 
1894     new_io->local  = io->local;
1895     new_io->remote = Parrot_pmc_new(interp, enum_class_Sockaddr);
1896 
1897     new_io->os_handle = Parrot_io_internal_accept(interp, io->os_handle, new_io->remote);
1898 
1899     return new_pmc;
1900 }
1901 
1902 /*
1903 
1904 =item C<PMC * Parrot_io_socket_new(PARROT_INTERP, INTVAL flags)>
1905 
1906 Creates a new I/O socket object. The value of C<flags> is set
1907 in the returned PMC.
1908 
1909 =cut
1910 
1911 */
1912 
1913 PARROT_EXPORT
1914 PARROT_WARN_UNUSED_RESULT
1915 PARROT_CANNOT_RETURN_NULL
1916 PMC *
Parrot_io_socket_new(PARROT_INTERP,INTVAL flags)1917 Parrot_io_socket_new(PARROT_INTERP, INTVAL flags)
1918 {
1919     ASSERT_ARGS(Parrot_io_socket_new)
1920     PMC * const sock = io_get_new_socket(interp);
1921     Parrot_io_set_flags(interp, sock, flags);
1922     return sock;
1923 }
1924 
1925 /*
1926 
1927 =item C<INTVAL Parrot_io_get_flags(PARROT_INTERP, PMC *handle)>
1928 
1929 Gets the current handle flags.
1930 
1931 =item C<void Parrot_io_set_flags(PARROT_INTERP, PMC *handle, INTVAL flags)>
1932 
1933 Sets the current handle flags.
1934 
1935 =cut
1936 
1937 */
1938 
1939 PARROT_WARN_UNUSED_RESULT
1940 INTVAL
Parrot_io_get_flags(PARROT_INTERP,ARGIN (PMC * handle))1941 Parrot_io_get_flags(PARROT_INTERP, ARGIN(PMC *handle))
1942 {
1943     ASSERT_ARGS(Parrot_io_get_flags)
1944     if (PMC_IS_NULL(handle))
1945         Parrot_ex_throw_from_c_noargs(interp, EXCEPTION_PIO_ERROR,
1946             "Cannot get flags for null or invalid PMC");
1947     {
1948         const IO_VTABLE * const vtable = IO_GET_VTABLE(interp, handle);
1949         return vtable->get_flags(interp, handle);
1950     }
1951 }
1952 
1953 void
Parrot_io_set_flags(PARROT_INTERP,ARGIN (PMC * handle),INTVAL flags)1954 Parrot_io_set_flags(PARROT_INTERP, ARGIN(PMC *handle), INTVAL flags)
1955 {
1956     ASSERT_ARGS(Parrot_io_set_flags)
1957     if (PMC_IS_NULL(handle))
1958         Parrot_ex_throw_from_c_noargs(interp, EXCEPTION_PIO_ERROR,
1959             "Cannot set flags for null or invalid PMC");
1960     {
1961         const IO_VTABLE * const vtable = IO_GET_VTABLE(interp, handle);
1962         vtable->set_flags(interp, handle, flags);
1963     }
1964 }
1965 
1966 /*
1967 
1968 =item C<PIOHANDLE Parrot_io_get_os_handle(PARROT_INTERP, PMC *handle)>
1969 
1970 Gets the OS handle (socket, file descriptor, etc) for the C<handle> PMC.
1971 
1972 =cut
1973 
1974 */
1975 
1976 PARROT_WARN_UNUSED_RESULT
1977 PIOHANDLE
Parrot_io_get_os_handle(PARROT_INTERP,ARGIN (PMC * handle))1978 Parrot_io_get_os_handle(PARROT_INTERP, ARGIN(PMC *handle))
1979 {
1980     ASSERT_ARGS(Parrot_io_get_os_handle)
1981     if (PMC_IS_NULL(handle))
1982         Parrot_ex_throw_from_c_noargs(interp, EXCEPTION_PIO_ERROR,
1983             "Cannot get a PIOHANDLE from a NULL or invalid PMC");
1984     {
1985         const IO_VTABLE * const vtable = IO_GET_VTABLE(interp, handle);
1986         return vtable->get_piohandle(interp, handle);
1987     }
1988 }
1989 
1990 /*
1991 
1992 =item C<void Parrot_io_set_buffer_mode(PARROT_INTERP, PMC *handle, STRING
1993 *mode)>
1994 
1995 Sets up buffering on C<handle> according to string C<mode>. This is a function
1996 for legacy compatibility and will disappear eventually. Do not use.
1997 
1998 =item C<STRING * Parrot_io_get_buffer_mode(PARROT_INTERP, PMC *handle)>
1999 
2000 Gets a string representation of the current buffer settings for C<handle>.This
2001 is a function for legacy compatibility and will disappear eventually. Do not
2002 use.
2003 
2004 =item C<INTVAL Parrot_io_buffer_size(PARROT_INTERP, PMC *handle, INTVAL size,
2005 INTVAL has_size)>
2006 
2007 Legacy routine to pretend get/set buffer size info for the old FileHandle
2008 interface.
2009 
2010 =cut
2011 
2012 */
2013 
2014 void
Parrot_io_set_buffer_mode(PARROT_INTERP,ARGMOD (PMC * handle),ARGIN (STRING * mode))2015 Parrot_io_set_buffer_mode(PARROT_INTERP, ARGMOD(PMC *handle), ARGIN(STRING *mode))
2016 {
2017     ASSERT_ARGS(Parrot_io_set_buffer_mode)
2018 
2019     /* This is a compatibility function for old-style buffer setting by mode
2020        name. A newer interface will need to be used with the new buffering
2021        system to take advantage of all its power. Notice that the new system
2022        uses separate read/write buffers, so we have to act on them separately.
2023     */
2024     if (STRING_equal(interp, mode, CONST_STRING(interp, "unbuffered"))) {
2025         Parrot_io_buffer_remove_from_handle(interp, handle, IO_PTR_IDX_READ_BUFFER);
2026         Parrot_io_buffer_remove_from_handle(interp, handle, IO_PTR_IDX_WRITE_BUFFER);
2027     }
2028     else if (STRING_equal(interp, mode, CONST_STRING(interp, "line-buffered"))) {
2029         Parrot_io_buffer_add_to_handle(interp, handle, IO_PTR_IDX_READ_BUFFER, BUFFER_SIZE_ANY,
2030                                        PIO_BF_LINEBUF);
2031         Parrot_io_buffer_add_to_handle(interp, handle, IO_PTR_IDX_WRITE_BUFFER, BUFFER_SIZE_ANY,
2032                                        PIO_BF_LINEBUF);
2033     }
2034     else if (STRING_equal(interp, mode, CONST_STRING(interp, "full-buffered"))) {
2035         Parrot_io_buffer_add_to_handle(interp, handle, IO_PTR_IDX_READ_BUFFER, BUFFER_SIZE_ANY,
2036                                        PIO_BF_BLKBUF);
2037         Parrot_io_buffer_add_to_handle(interp, handle, IO_PTR_IDX_WRITE_BUFFER, BUFFER_SIZE_ANY,
2038                                        PIO_BF_BLKBUF);
2039     }
2040     else
2041         Parrot_ex_throw_from_c_args(interp, NULL, EXCEPTION_PIO_ERROR,
2042                 "Unknown buffering type %Ss", mode);
2043 }
2044 
2045 PARROT_CANNOT_RETURN_NULL
2046 PARROT_WARN_UNUSED_RESULT
2047 STRING *
Parrot_io_get_buffer_mode(PARROT_INTERP,ARGMOD (PMC * handle))2048 Parrot_io_get_buffer_mode(PARROT_INTERP, ARGMOD(PMC *handle))
2049 {
2050     ASSERT_ARGS(Parrot_io_get_buffer_mode)
2051     /* This is a compatibility function for old style buffer mode names. This
2052        is a hack, because the current system is much more flexible than the
2053        old system and the buffer configuration on a handle cannot really be
2054        described in a one-word string like it could previously. Do whatever it
2055        takes to replicate the old behavior (even if it doesn't make sense). */
2056 
2057     IO_BUFFER * const read_buffer = IO_GET_READ_BUFFER(interp, handle);
2058     IO_BUFFER * const write_buffer = IO_GET_WRITE_BUFFER(interp, handle);
2059 
2060     if (!read_buffer && !write_buffer)
2061         return CONST_STRING(interp, "unbuffered");
2062 
2063     if (write_buffer->flags & PIO_BF_LINEBUF)
2064         return CONST_STRING(interp, "line-buffered");
2065 
2066     return CONST_STRING(interp, "full-buffered");
2067 }
2068 
2069 PARROT_WARN_UNUSED_RESULT
2070 INTVAL
Parrot_io_buffer_size(PARROT_INTERP,ARGMOD (PMC * handle),INTVAL size,INTVAL has_size)2071 Parrot_io_buffer_size(PARROT_INTERP, ARGMOD(PMC *handle), INTVAL size, INTVAL has_size)
2072 {
2073     ASSERT_ARGS(Parrot_io_buffer_size)
2074 
2075     if (has_size)
2076         Parrot_io_buffer_add_to_handle(interp, handle, IO_PTR_IDX_READ_BUFFER,
2077                                                            size, PIO_BF_BLKBUF);
2078     {
2079         IO_BUFFER * const read_buffer = IO_GET_READ_BUFFER(interp, handle);
2080         return read_buffer == NULL ? 0 : read_buffer->buffer_size;
2081     }
2082 }
2083 
2084 
2085 /*
2086 
2087 =item C<STRING * Parrot_io_reencode_string_for_handle(PARROT_INTERP, PMC
2088 *handle, STRING *str)>
2089 
2090 Verify that the given string matches the encoding for the given handle. If so,
2091 return it directly. If not, create a new string with the proper encoding and
2092 return that.
2093 
2094 =cut
2095 
2096 */
2097 
2098 PARROT_CANNOT_RETURN_NULL
2099 PARROT_WARN_UNUSED_RESULT
2100 STRING *
Parrot_io_reencode_string_for_handle(PARROT_INTERP,ARGIN (PMC * handle),ARGIN_NULLOK (STRING * str))2101 Parrot_io_reencode_string_for_handle(PARROT_INTERP, ARGIN(PMC *handle), ARGIN_NULLOK(STRING *str))
2102 {
2103     ASSERT_ARGS(Parrot_io_reencode_string_for_handle)
2104 
2105     if (PMC_IS_NULL(handle))
2106         Parrot_ex_throw_from_c_noargs(interp, EXCEPTION_PIO_ERROR,
2107             "Handle may not be null");
2108     if (STRING_IS_NULL(str))
2109         return STRINGNULL;
2110 
2111     {
2112         const IO_VTABLE * const vtable = IO_GET_VTABLE(interp, handle);
2113         const STR_VTABLE * const encoding = vtable->get_encoding(interp, handle);
2114 
2115         if (encoding != NULL && str->encoding != encoding)
2116             return encoding->to_encoding(interp, str);
2117         return str;
2118     }
2119 }
2120 
2121 /*
2122 
2123 =item C<INTVAL Parrot_io_getprotobyname(PARROT_INTERP, STRING * name)>
2124 
2125 Return a protocol number given a protocol name.
2126 
2127 =cut
2128 
2129 */
2130 
2131 
2132 
2133 PARROT_EXPORT
2134 PARROT_WARN_UNUSED_RESULT
2135 INTVAL
Parrot_io_getprotobyname(PARROT_INTERP,ARGIN (STRING * name))2136 Parrot_io_getprotobyname(PARROT_INTERP, ARGIN(STRING * name))
2137 {
2138     ASSERT_ARGS(Parrot_io_getprotobyname)
2139 
2140     return Parrot_io_internal_getprotobyname(interp, name);
2141 }
2142 
2143 
2144 
2145 /*
2146 
2147 =back
2148 
2149 =cut
2150 
2151 */
2152 
2153 /*
2154  * Local variables:
2155  *   c-file-style: "parrot"
2156  * End:
2157  * vim: expandtab shiftwidth=4 cinoptions='\:2=2' :
2158  */
2159