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