2 Copyright (C) 2008-2010, Parrot Foundation.
7 src/pmc/stringhandle.pmc - StringHandle PMC
11 The StringHandle PMC performs I/O operations, but on an internal string rather
12 than an external file. Commonly used as a mock FileHandle for testing.
18 #include "../src/io/io_private.h"
20 /* HEADERIZER HFILE: none */
21 /* HEADERIZER BEGIN: static */
22 /* Don't modify between HEADERIZER BEGIN / HEADERIZER END. Your changes will be lost. */
25 static int encoding_is_utf8(PARROT_INTERP, ARGIN_NULLOK(const STRING *s))
26 __attribute__nonnull__(1);
28 #define ASSERT_ARGS_encoding_is_utf8 __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
29 PARROT_ASSERT_ARG(interp))
30 /* Don't modify between HEADERIZER BEGIN / HEADERIZER END. Your changes will be lost. */
31 /* HEADERIZER END: static */
35 =head2 Internal Functions
39 =item C<static int encoding_is_utf8(PARROT_INTERP, const STRING *s)>
41 Helper function for internal usage. Return 1 if the string argument is
42 not null and has utf8 encoding, 0 otherwise.
52 encoding_is_utf8(PARROT_INTERP, ARGIN_NULLOK(const STRING *s))
54 ASSERT_ARGS(encoding_is_utf8)
55 if (STRING_IS_NULL(s))
58 return Parrot_str_equal(interp, s, CONST_STRING(interp, "utf8"));
61 pmclass StringHandle extends Handle auto_attrs {
62 ATTR INTVAL flags; /* Filehandle flags */
63 ATTR STRING *stringhandle; /* The string data */
64 ATTR STRING *mode; /* The mode string used in open */
65 ATTR STRING *encoding; /* The encoding for read/write */
66 ATTR STRING *filename; /* A mock path and filename */
67 ATTR INTVAL read_offset; /* Position, for reading bytes */
71 =head2 Vtable Functions
77 Initializes a newly created StringHandle object.
84 Parrot_StringHandle_attributes * const data_struct =
85 (Parrot_StringHandle_attributes *) PMC_data(SELF);
87 data_struct->flags = 0;
88 data_struct->stringhandle = NULL;
89 data_struct->mode = NULL;
90 data_struct->encoding = NULL;
91 data_struct->filename = NULL;
92 data_struct->read_offset = 0;
94 PObj_custom_mark_SET(SELF);
101 Create a copy of the stringhandle.
107 VTABLE PMC *clone() {
108 Parrot_StringHandle_attributes * const old_struct = PARROT_STRINGHANDLE(SELF);
109 PMC * const copy = Parrot_pmc_new(INTERP, enum_class_StringHandle);
110 Parrot_StringHandle_attributes * const data_struct = PARROT_STRINGHANDLE(copy);
112 data_struct->stringhandle = old_struct->stringhandle;
113 data_struct->mode = old_struct->mode;
114 data_struct->encoding = old_struct->encoding;
115 data_struct->flags = old_struct->flags;
124 Mark active stringhandle data as live.
131 Parrot_StringHandle_attributes * const data_struct = PARROT_STRINGHANDLE(SELF);
132 Parrot_gc_mark_STRING_alive(INTERP, data_struct->stringhandle);
133 Parrot_gc_mark_STRING_alive(INTERP, data_struct->mode);
134 Parrot_gc_mark_STRING_alive(INTERP, data_struct->encoding);
135 Parrot_gc_mark_STRING_alive(INTERP, data_struct->filename);
140 =item C<INTVAL get_bool()>
142 Returns whether the StringHandle has reached the end of the file.
148 VTABLE INTVAL get_bool() {
149 STRING *stringhandle;
150 GET_ATTR_stringhandle(INTERP, SELF, stringhandle);
152 if (STRING_IS_NULL(stringhandle))
167 =item C<METHOD open(STRING *filename :optional, STRING *mode :optional)>
169 Opens a string handle with the given mode. The filename is not used, but is
176 METHOD open(STRING *filename :optional, INTVAL got_filename :opt_flag,
177 STRING *mode :optional, INTVAL got_mode :opt_flag) {
178 STRING *open_mode, *old_string;
181 if (got_mode && !STRING_IS_NULL(mode))
182 SET_ATTR_mode(INTERP, SELF, mode);
184 if (got_filename && !STRING_IS_NULL(filename))
185 SET_ATTR_filename(INTERP, SELF, filename);
188 /* If StringHandle hasn't already been initialized, create a new string. */
189 GET_ATTR_stringhandle(INTERP, SELF, old_string);
190 if (STRING_IS_NULL(old_string)) {
194 GET_ATTR_encoding(INTERP, SELF, encoding);
195 if (encoding_is_utf8(INTERP, encoding))
196 new_string = Parrot_str_new_init(INTERP, "", 0,
197 Parrot_utf8_encoding_ptr, 0);
199 new_string = CONST_STRING(INTERP, "");
201 SET_ATTR_stringhandle(INTERP, SELF, new_string);
204 /* Set a default mode of read-only. */
205 GET_ATTR_mode(INTERP, SELF, open_mode);
206 if (STRING_IS_NULL(open_mode)) {
207 open_mode = CONST_STRING(INTERP, "r");
208 SET_ATTR_mode(INTERP, SELF, open_mode);
211 flags = Parrot_io_parse_open_flags(INTERP, open_mode);
212 SET_ATTR_flags(INTERP, SELF, flags);
219 =item C<METHOD close()>
221 Reset some core data for the StringHandle, but don't delete the string data, as
222 it may be wanted later (for capturing the results).
229 SET_ATTR_read_offset(INTERP, SELF, 0);
235 =item C<METHOD is_closed()>
237 Check if the StringHandle is open.
244 STRING *stringhandle;
246 GET_ATTR_stringhandle(INTERP, SELF, stringhandle);
247 status = STRING_IS_NULL(stringhandle);
248 RETURN(INTVAL status);
253 =item C<METHOD read(INTVAL bytes)>
255 Read the entire contents of the stringhandle and return it in a string. The
256 C<bytes> argument is currently ignored.
262 METHOD read(INTVAL length) {
263 STRING * const string_result = Parrot_io_reads(INTERP, SELF, length);
264 RETURN(STRING *string_result);
269 =item C<METHOD readline()>
271 Read a line from the stringhandle and return it in a string. (Currently only
272 responds to "\n" newlines.)
279 STRING * const string_result = Parrot_io_readline(INTERP, SELF);
280 RETURN(STRING *string_result);
285 =item METHOD readall(STRING *name);
287 Read the entire contents of the StringHandle into a Parrot string. On a
288 StringHandle object that isn't opened yet, returns an empty string.
294 METHOD readall(STRING *name :optional, INTVAL got_name :opt_flag) {
295 STRING *string_result;
297 GET_ATTR_stringhandle(INTERP, SELF, string_result);
298 if (STRING_IS_NULL(string_result)) {
300 GET_ATTR_encoding(INTERP, SELF, encoding);
301 if (encoding_is_utf8(INTERP, encoding))
302 string_result = Parrot_str_new_init(INTERP, "", 0,
303 Parrot_utf8_encoding_ptr, 0);
305 string_result = CONST_STRING(INTERP, "");
308 RETURN(STRING *string_result);
313 =item C<METHOD flush()>
315 Clear the StringHandle by resetting it to a null value.
322 Parrot_io_flush(INTERP, SELF);
327 =item C<METHOD print([INTVAL|FLOATVAL|STRING *|PMC*] value)>
329 Print the passed in integer, number, string, or PMC to the stringhandle.
330 (Integers, numbers, and strings are auto-boxed as PMCs.)
336 METHOD print(PMC *to_print) {
337 STRING * const string_to_print = VTABLE_get_string(INTERP, to_print);
339 Parrot_io_putps(INTERP, SELF, string_to_print);
344 =item C<METHOD puts(STRING *value)>
346 Print the string to the stringhandle.
352 METHOD puts(STRING *to_print) {
353 INTVAL flags, status;
354 STRING *old_string, *new_string;
356 GET_ATTR_stringhandle(INTERP, SELF, old_string);
357 if (STRING_IS_NULL(old_string))
358 Parrot_ex_throw_from_c_args(INTERP, NULL, EXCEPTION_PIO_ERROR,
359 "Cannot write to a closed filehandle");
361 GET_ATTR_flags(INTERP, SELF, flags);
362 if (!(flags & PIO_F_WRITE))
363 Parrot_ex_throw_from_c_args(INTERP, NULL, EXCEPTION_PIO_ERROR,
364 "Cannot write to a filehandle not opened for write");
366 new_string = Parrot_str_concat(INTERP, old_string, to_print);
368 SET_ATTR_stringhandle(INTERP, SELF, new_string);
370 status = Parrot_str_byte_length(INTERP, new_string);
371 RETURN(INTVAL status);
376 =item C<METHOD buffer_type(STRING *new_type :optional)>
378 Set or retrieve the buffering attribute for the stringhandle. This attribute is
379 ignored, but stored for mocking.
385 METHOD buffer_type(STRING *new_type :optional, INTVAL got_type :opt_flag) {
387 STRING * const nobuffer_string = CONST_STRING(INTERP, "unbuffered");
388 STRING * const linebuffer_string = CONST_STRING(INTERP, "line-buffered");
389 STRING * const fullbuffer_string = CONST_STRING(INTERP, "full-buffered");
391 GET_ATTR_flags(INTERP, SELF, flags);
394 if (Parrot_str_equal(INTERP, new_type, nobuffer_string)) {
395 flags &= ~ PIO_F_LINEBUF;
396 flags &= ~ PIO_F_BLKBUF;
398 else if (Parrot_str_equal(INTERP, new_type, linebuffer_string)) {
399 flags |= PIO_F_LINEBUF;
400 flags &= ~ PIO_F_BLKBUF;
402 else if (Parrot_str_equal(INTERP, new_type, fullbuffer_string)) {
403 flags &= ~ PIO_F_LINEBUF;
404 flags |= PIO_F_BLKBUF;
407 SET_ATTR_flags(INTERP, SELF, flags);
410 if (flags & PIO_F_LINEBUF)
411 RETURN(STRING *linebuffer_string);
412 else if (flags & PIO_F_BLKBUF)
413 RETURN(STRING *fullbuffer_string);
414 RETURN(STRING *nobuffer_string);
419 =item C<METHOD buffer_size(INTVAL new_size :optional)>
421 Returns the current size of the stringhandle.
427 METHOD buffer_size(INTVAL new_size :optional, INTVAL got_size :opt_flag) {
429 STRING *stringhandle;
431 GET_ATTR_stringhandle(INTERP, SELF, stringhandle);
433 if (STRING_IS_NULL(stringhandle))
435 buffer_size = Parrot_str_byte_length(INTERP, stringhandle);
437 RETURN(INTVAL buffer_size);
443 =item C<METHOD mode()>
445 Retrieve the read mode string for the stringhandle.
453 GET_ATTR_mode(INTERP, SELF, mode);
454 RETURN(STRING *mode);
459 =item C<METHOD encoding(STRING *new_encoding)>
461 Set or retrieve the encoding attribute (a string name of the selected encoding
462 scheme) for the stringhandle.
468 METHOD encoding(STRING *new_encoding :optional, INTVAL got_encoding :opt_flag) {
472 SET_ATTR_encoding(INTERP, SELF, new_encoding);
473 RETURN(STRING *new_encoding);
476 GET_ATTR_encoding(INTERP, SELF, encoding);
477 RETURN(STRING *encoding);
482 =item C<METHOD eof()>
484 Check if the StringHandle is at end-of-file (if it has read to the end of the
492 STRING *stringhandle;
494 GET_ATTR_stringhandle(INTERP, SELF, stringhandle);
495 GET_ATTR_read_offset(INTERP, SELF, offset);
497 if (offset >= Parrot_str_byte_length(INTERP, stringhandle))
506 =item C<METHOD get_fd()>
508 StringHandles do not use integer file descriptors, so always returns an error
533 * c-file-style: "parrot"
535 * vim: expandtab shiftwidth=4: