fix codetest failure - ASSERT_ARGS does not have a ; after and
[parrot.git] / src / pmc / stringhandle.pmc
blobf94e41c0bddb4918c7e7d87d8e0a6c6e5a654a7f
1 /*
2 Copyright (C) 2008-2010, Parrot Foundation.
3 $Id$
5 =head1 NAME
7 src/pmc/stringhandle.pmc - StringHandle PMC
9 =head1 DESCRIPTION
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.
14 =cut
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. */
24 PARROT_INLINE
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
37 =over 4
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.
44 =back
46 =cut
50 PARROT_INLINE
51 static int
52 encoding_is_utf8(PARROT_INTERP, ARGIN_NULLOK(const STRING *s))
54     ASSERT_ARGS(encoding_is_utf8)
55     if (STRING_IS_NULL(s))
56         return 0;
57     else
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
73 =over 4
75 =item C<void init()>
77 Initializes a newly created StringHandle object.
79 =cut
83     VTABLE void init() {
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);
95     }
99 =item C<PMC *clone()>
101 Create a copy of the stringhandle.
103 =cut
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;
117         return copy;
118     }
122 =item C<void mark()>
124 Mark active stringhandle data as live.
126 =cut
130     VTABLE void mark() {
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);
136     }
140 =item C<INTVAL get_bool()>
142 Returns whether the StringHandle has reached the end of the file.
144 =cut
148     VTABLE INTVAL get_bool() {
149         STRING *stringhandle;
150         GET_ATTR_stringhandle(INTERP, SELF, stringhandle);
152         if (STRING_IS_NULL(stringhandle))
153             return 0;
155         return 1;
156     }
161 =back
163 =head2 Methods
165 =over 4
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
170 stored for mocking.
172 =cut
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;
179         INTVAL flags;
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)) {
191             STRING *new_string;
192             STRING *encoding;
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);
198             else
199                 new_string = CONST_STRING(INTERP, "");
201             SET_ATTR_stringhandle(INTERP, SELF, new_string);
202         }
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);
209         }
211         flags = Parrot_io_parse_open_flags(INTERP, open_mode);
212         SET_ATTR_flags(INTERP, SELF, flags);
214         RETURN(PMC *SELF);
215     }
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).
224 =cut
228     METHOD close() {
229         SET_ATTR_read_offset(INTERP, SELF, 0);
230         RETURN(INTVAL 0);
231     }
235 =item C<METHOD is_closed()>
237 Check if the StringHandle is open.
239 =cut
243     METHOD is_closed() {
244         STRING *stringhandle;
245         INTVAL status;
246         GET_ATTR_stringhandle(INTERP, SELF, stringhandle);
247         status = STRING_IS_NULL(stringhandle);
248         RETURN(INTVAL status);
249     }
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.
258 =cut
262     METHOD read(INTVAL length) {
263         STRING * const string_result = Parrot_io_reads(INTERP, SELF, length);
264         RETURN(STRING *string_result);
265     }
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.)
274 =cut
278     METHOD readline() {
279         STRING * const string_result = Parrot_io_readline(INTERP, SELF);
280         RETURN(STRING *string_result);
281     }
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.
290 =cut
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)) {
299             STRING *encoding;
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);
304             else
305                 string_result = CONST_STRING(INTERP, "");
306         }
308         RETURN(STRING *string_result);
309     }
313 =item C<METHOD flush()>
315 Clear the StringHandle by resetting it to a null value.
317 =cut
321     METHOD flush() {
322         Parrot_io_flush(INTERP, SELF);
323     }
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.)
332 =cut
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);
340     }
344 =item C<METHOD puts(STRING *value)>
346 Print the string to the stringhandle.
348 =cut
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);
372     }
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.
381 =cut
385     METHOD buffer_type(STRING *new_type :optional, INTVAL got_type :opt_flag) {
386         INTVAL flags;
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);
393         if (got_type) {
394             if (Parrot_str_equal(INTERP, new_type, nobuffer_string)) {
395                 flags &= ~ PIO_F_LINEBUF;
396                 flags &= ~ PIO_F_BLKBUF;
397             }
398             else if (Parrot_str_equal(INTERP, new_type, linebuffer_string)) {
399                 flags |=   PIO_F_LINEBUF;
400                 flags &= ~ PIO_F_BLKBUF;
401             }
402             else if (Parrot_str_equal(INTERP, new_type, fullbuffer_string)) {
403                 flags &= ~ PIO_F_LINEBUF;
404                 flags |=   PIO_F_BLKBUF;
405             }
407             SET_ATTR_flags(INTERP, SELF, flags);
408         }
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);
415     }
419 =item C<METHOD buffer_size(INTVAL new_size :optional)>
421 Returns the current size of the stringhandle.
423 =cut
427     METHOD buffer_size(INTVAL new_size :optional, INTVAL got_size :opt_flag) {
428         INTVAL buffer_size;
429         STRING *stringhandle;
431         GET_ATTR_stringhandle(INTERP, SELF, stringhandle);
433         if (STRING_IS_NULL(stringhandle))
434             RETURN(INTVAL 0);
435         buffer_size = Parrot_str_byte_length(INTERP, stringhandle);
437         RETURN(INTVAL buffer_size);
439     }
443 =item C<METHOD mode()>
445 Retrieve the read mode string for the stringhandle.
447 =cut
451     METHOD mode() {
452         STRING *mode;
453         GET_ATTR_mode(INTERP, SELF, mode);
454         RETURN(STRING *mode);
455     }
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.
464 =cut
468     METHOD encoding(STRING *new_encoding :optional, INTVAL got_encoding :opt_flag) {
469         STRING *encoding;
471         if (got_encoding) {
472             SET_ATTR_encoding(INTERP, SELF, new_encoding);
473             RETURN(STRING *new_encoding);
474         }
476         GET_ATTR_encoding(INTERP, SELF, encoding);
477         RETURN(STRING *encoding);
478     }
482 =item C<METHOD eof()>
484 Check if the StringHandle is at end-of-file (if it has read to the end of the
485 string data).
487 =cut
491     METHOD eof() {
492         STRING *stringhandle;
493         UINTVAL offset;
494         GET_ATTR_stringhandle(INTERP, SELF, stringhandle);
495         GET_ATTR_read_offset(INTERP, SELF, offset);
497         if (offset >= Parrot_str_byte_length(INTERP, stringhandle))
498             RETURN(INTVAL 1);
500         RETURN(INTVAL 0);
501     }
506 =item C<METHOD get_fd()>
508 StringHandles do not use integer file descriptors, so always returns an error
509 value.
511 =cut
515     METHOD get_fd() {
516         UNUSED(INTERP);
517         RETURN(INTVAL -1);
518     }
523 =back
525 =cut
529 } /* end pmclass */
532  * Local variables:
533  *   c-file-style: "parrot"
534  * End:
535  * vim: expandtab shiftwidth=4:
536  */