MVMString * MVM_string_decodestream_get_chars(MVMThreadContext *tc, MVMDecodeStream *ds, MVMint32 chars, MVMint64 eof) { MVMint32 missing; /* If we request nothing, give empty string. */ if (chars == 0) return tc->instance->str_consts.empty; /* If we don't already have enough chars, try and decode more. */ missing = missing_chars(tc, ds, chars); ds->result_size_guess = missing; if (missing) run_decode(tc, ds, &missing, NULL, DECODE_NOT_EOF); /* If we've got enough, assemble a string. Otherwise, flag EOF and retry, * falling back to returning what's available. */ if (missing_chars(tc, ds, chars) == 0) { return take_chars(tc, ds, chars, 0); } else if (eof) { reached_eof(tc, ds); return missing_chars(tc, ds, chars) == 0 ? take_chars(tc, ds, chars, 0) : MVM_string_decodestream_get_all(tc, ds); } else { return NULL; } }
/* Variant of MVM_string_decodestream_get_until_sep that is called when we * reach EOF. Trims the final separator if there is one, or returns the last * line without the EOF marker. */ MVMString * MVM_string_decodestream_get_until_sep_eof(MVMThreadContext *tc, MVMDecodeStream *ds, MVMDecodeStreamSeparators *sep_spec, MVMint32 chomp) { MVMint32 sep_loc, sep_length; /* Decode anything remaining and flush normalization buffer. */ reached_eof(tc, ds); /* Look for separator, which should by now be at the end, and chomp it * off if needed. */ sep_loc = find_separator(tc, ds, sep_spec, &sep_length); if (sep_loc) return take_chars(tc, ds, sep_loc, chomp ? sep_length : 0); /* Otherwise, take all remaining chars. */ return MVM_string_decodestream_get_all(tc, ds); }
/* Decodes all the buffers, producing a string containing all the decoded * characters. */ MVMString * MVM_string_decodestream_get_all(MVMThreadContext *tc, MVMDecodeStream *ds) { MVMString *result = (MVMString *)MVM_repr_alloc_init(tc, tc->instance->VMString); result->body.storage_type = MVM_STRING_GRAPHEME_32; /* Decode anything remaining and flush normalization buffer. */ reached_eof(tc, ds); /* If there's no codepoint buffer, then return the empty string. */ if (!ds->chars_head) { result->body.storage.blob_32 = NULL; result->body.num_graphs = 0; } /* If there's exactly one resulting codepoint buffer and we swallowed none * of it, just use it. */ else if (ds->chars_head == ds->chars_tail && ds->chars_head_pos == 0) { /* Set up result string. */ result->body.storage.blob_32 = ds->chars_head->chars; result->body.num_graphs = ds->chars_head->length; /* Don't free the buffer's memory itself, just the holder, as we * stole that for the buffer into the string above. */ MVM_free(ds->chars_head); ds->chars_head = ds->chars_tail = NULL; } /* Otherwise, need to assemble all the things. */ else { /* Calculate length. */ MVMint32 length = 0, pos = 0; MVMDecodeStreamChars *cur_chars = ds->chars_head; while (cur_chars) { if (cur_chars == ds->chars_head) length += cur_chars->length - ds->chars_head_pos; else length += cur_chars->length; cur_chars = cur_chars->next; } /* Allocate a result buffer of the right size. */ result->body.storage.blob_32 = MVM_malloc(length * sizeof(MVMGrapheme32)); result->body.num_graphs = length; /* Copy all the things into the target, freeing as we go. */ cur_chars = ds->chars_head; while (cur_chars) { if (cur_chars == ds->chars_head) { MVMint32 to_copy = ds->chars_head->length - ds->chars_head_pos; memcpy(result->body.storage.blob_32 + pos, cur_chars->chars + ds->chars_head_pos, cur_chars->length * sizeof(MVMGrapheme32)); pos += to_copy; } else { memcpy(result->body.storage.blob_32 + pos, cur_chars->chars, cur_chars->length * sizeof(MVMGrapheme32)); pos += cur_chars->length; } cur_chars = cur_chars->next; } ds->chars_head = ds->chars_tail = NULL; } return result; }
/* Decodes all the buffers, signals EOF to flush any normalization buffers, and * returns a string of all decoded chars. */ MVMString * MVM_string_decodestream_get_all(MVMThreadContext *tc, MVMDecodeStream *ds) { reached_eof(tc, ds); return get_all_in_buffer(tc, ds); }