📄 giochannel.c
字号:
if (BUF_LEN (USE_BUF (channel)) == 0) { g_assert (status != G_IO_STATUS_NORMAL); if (status == G_IO_STATUS_EOF && channel->encoding && BUF_LEN (channel->read_buf) > 0) { g_set_error (error, G_CONVERT_ERROR, G_CONVERT_ERROR_PARTIAL_INPUT, _("Leftover unconverted data in read buffer")); status = G_IO_STATUS_ERROR; } if (bytes_read) *bytes_read = 0; return status; } if (status == G_IO_STATUS_ERROR) g_clear_error (error); got_bytes = MIN (count, BUF_LEN (USE_BUF (channel))); g_assert (got_bytes > 0); if (channel->encoding) /* Don't validate for NULL encoding, binary safe */ { gchar *nextchar, *prevchar; g_assert (USE_BUF (channel) == channel->encoded_read_buf); nextchar = channel->encoded_read_buf->str; do { prevchar = nextchar; nextchar = g_utf8_next_char (nextchar); g_assert (nextchar != prevchar); /* Possible for *prevchar of -1 or -2 */ } while (nextchar < channel->encoded_read_buf->str + got_bytes); if (nextchar > channel->encoded_read_buf->str + got_bytes) got_bytes = prevchar - channel->encoded_read_buf->str; g_assert (got_bytes > 0 || count < 6); } memcpy (buf, USE_BUF (channel)->str, got_bytes); g_string_erase (USE_BUF (channel), 0, got_bytes); if (bytes_read) *bytes_read = got_bytes; return G_IO_STATUS_NORMAL;}/** * g_io_channel_read_unichar: * @channel: a #GIOChannel * @thechar: a location to return a character * @error: A location to return an error of type #GConvertError * or #GIOChannelError * * This function cannot be called on a channel with %NULL encoding. * * Return value: a #GIOStatus **/GIOStatusg_io_channel_read_unichar (GIOChannel *channel, gunichar *thechar, GError **error){ GIOStatus status = G_IO_STATUS_NORMAL; g_return_val_if_fail (channel != NULL, G_IO_STATUS_ERROR); g_return_val_if_fail (channel->encoding != NULL, G_IO_STATUS_ERROR); g_return_val_if_fail ((error == NULL) || (*error == NULL), G_IO_STATUS_ERROR); g_return_val_if_fail (channel->is_readable, G_IO_STATUS_ERROR); while (BUF_LEN (channel->encoded_read_buf) == 0 && status == G_IO_STATUS_NORMAL) status = g_io_channel_fill_buffer (channel, error); /* Only return an error if we have no data */ if (BUF_LEN (USE_BUF (channel)) == 0) { g_assert (status != G_IO_STATUS_NORMAL); if (status == G_IO_STATUS_EOF && BUF_LEN (channel->read_buf) > 0) { g_set_error (error, G_CONVERT_ERROR, G_CONVERT_ERROR_PARTIAL_INPUT, _("Leftover unconverted data in read buffer")); status = G_IO_STATUS_ERROR; } if (thechar) *thechar = (gunichar) -1; return status; } if (status == G_IO_STATUS_ERROR) g_clear_error (error); if (thechar) *thechar = g_utf8_get_char (channel->encoded_read_buf->str); g_string_erase (channel->encoded_read_buf, 0, g_utf8_next_char (channel->encoded_read_buf->str) - channel->encoded_read_buf->str); return G_IO_STATUS_NORMAL;}/** * g_io_channel_write_chars: * @channel: a #GIOChannel * @buf: a buffer to write data from * @count: the size of the buffer. If -1, the buffer * is taken to be a nul-terminated string. * @bytes_written: The number of bytes written. This can be nonzero * even if the return value is not %G_IO_STATUS_NORMAL. * If the return value is %G_IO_STATUS_NORMAL and the * channel is blocking, this will always be equal * to @count if @count >= 0. * @error: A location to return an error of type #GConvertError * or #GIOChannelError * * Replacement for g_io_channel_write() with the new API. * * On seekable channels with encodings other than %NULL or UTF-8, generic * mixing of reading and writing is not allowed. A call to g_io_channel_write_chars () * may only be made on a channel from which data has been read in the * cases described in the documentation for g_io_channel_set_encoding (). * * Return value: the status of the operation. **/GIOStatusg_io_channel_write_chars (GIOChannel *channel, const gchar *buf, gssize count, gsize *bytes_written, GError **error){ GIOStatus status; gssize wrote_bytes = 0; g_return_val_if_fail (channel != NULL, G_IO_STATUS_ERROR); g_return_val_if_fail ((error == NULL) || (*error == NULL), G_IO_STATUS_ERROR); g_return_val_if_fail (channel->is_writeable, G_IO_STATUS_ERROR); if ((count < 0) && buf) count = strlen (buf); if (count == 0) { if (bytes_written) *bytes_written = 0; return G_IO_STATUS_NORMAL; } g_return_val_if_fail (buf != NULL, G_IO_STATUS_ERROR); g_return_val_if_fail (count > 0, G_IO_STATUS_ERROR); /* Raw write case */ if (!channel->use_buffer) { gsize tmp_bytes; g_assert (!channel->write_buf || channel->write_buf->len == 0); g_assert (channel->partial_write_buf[0] == '\0'); status = channel->funcs->io_write (channel, buf, count, &tmp_bytes, error); if (bytes_written) *bytes_written = tmp_bytes; return status; } /* General case */ if (channel->is_seekable && (( BUF_LEN (channel->read_buf) > 0) || (BUF_LEN (channel->encoded_read_buf) > 0))) { if (channel->do_encode && BUF_LEN (channel->encoded_read_buf) > 0) { g_warning("Mixed reading and writing not allowed on encoded files"); return G_IO_STATUS_ERROR; } status = g_io_channel_seek_position (channel, 0, G_SEEK_CUR, error); if (status != G_IO_STATUS_NORMAL) { if (bytes_written) *bytes_written = 0; return status; } } if (!channel->write_buf) channel->write_buf = g_string_sized_new (channel->buf_size); while (wrote_bytes < count) { gsize space_in_buf; /* If the buffer is full, try a write immediately. In * the nonblocking case, this prevents the user from * writing just a little bit to the buffer every time * and never receiving an EAGAIN. */ if (channel->write_buf->len >= channel->buf_size) { gsize did_write = 0, this_time; do { status = channel->funcs->io_write (channel, channel->write_buf->str + did_write, channel->write_buf->len - did_write, &this_time, error); did_write += this_time; } while (status == G_IO_STATUS_NORMAL && did_write < MIN (channel->write_buf->len, MAX_CHAR_SIZE)); g_string_erase (channel->write_buf, 0, did_write); if (status != G_IO_STATUS_NORMAL) { if (status == G_IO_STATUS_AGAIN && wrote_bytes > 0) status = G_IO_STATUS_NORMAL; if (bytes_written) *bytes_written = wrote_bytes; return status; } } space_in_buf = MAX (channel->buf_size, channel->write_buf->allocated_len - 1) - channel->write_buf->len; /* 1 for NULL */ /* This is only true because g_io_channel_set_buffer_size () * ensures that channel->buf_size >= MAX_CHAR_SIZE. */ g_assert (space_in_buf >= MAX_CHAR_SIZE); if (!channel->encoding) { gssize write_this = MIN (space_in_buf, count - wrote_bytes); g_string_append_len (channel->write_buf, buf, write_this); buf += write_this; wrote_bytes += write_this; } else { const gchar *from_buf; gsize from_buf_len, from_buf_old_len, left_len; size_t err; gint errnum; if (channel->partial_write_buf[0] != '\0') { g_assert (wrote_bytes == 0); from_buf = channel->partial_write_buf; from_buf_old_len = strlen (channel->partial_write_buf); g_assert (from_buf_old_len > 0); from_buf_len = MIN (6, from_buf_old_len + count); memcpy (channel->partial_write_buf + from_buf_old_len, buf, from_buf_len - from_buf_old_len); } else { from_buf = buf; from_buf_len = count - wrote_bytes; from_buf_old_len = 0; }reconvert: if (!channel->do_encode) /* UTF-8 encoding */ { const gchar *badchar; gsize try_len = MIN (from_buf_len, space_in_buf); /* UTF-8, just validate, emulate g_iconv */ if (!g_utf8_validate (from_buf, try_len, &badchar)) { gunichar try_char; gsize incomplete_len = from_buf + try_len - badchar; left_len = from_buf + from_buf_len - badchar; try_char = g_utf8_get_char_validated (badchar, incomplete_len); switch (try_char) { case -2: g_assert (incomplete_len < 6); if (try_len == from_buf_len) { errnum = EINVAL; err = (size_t) -1; } else { errnum = 0; err = (size_t) 0; } break; case -1: g_warning ("Invalid UTF-8 passed to g_io_channel_write_chars()."); /* FIXME bail here? */ errnum = EILSEQ; err = (size_t) -1; break; default: g_assert_not_reached (); err = (size_t) -1; errnum = 0; /* Don't confunse the compiler */ } } else { err = (size_t) 0; errnum = 0; left_len = from_buf_len - try_len; } g_string_append_len (channel->write_buf, from_buf, from_buf_len - left_len); from_buf += from_buf_len - left_len; } else { gchar *outbuf; left_len = from_buf_len; g_string_set_size (channel->write_buf, channel->write_buf->len + space_in_buf); outbuf = channel->write_buf->str + channel->write_buf->len - space_in_buf; err = g_iconv (channel->write_cd, (gchar **) &from_buf, &left_len, &outbuf, &space_in_buf); errnum = errno; g_string_truncate (channel->write_buf, channel->write_buf->len - space_in_buf); } if (err == (size_t) -1) { switch (errnum) { case EINVAL: g_assert (left_len < 6); if (from_buf_old_len == 0) { /* Not from partial_write_buf */ memcpy (channel->partial_write_buf, from_buf, left_len); channel->partial_write_buf[left_len] = '\0'; if (bytes_written) *bytes_written = count; return G_IO_STATUS_NORMAL; } /* Working in partial_write_buf */ if (left_len == from_buf_len) { /* Didn't convert anything, must still have * less than a full character */ g_assert (count == from_buf_len - from_buf_old_len); channel->partial_write_buf[from_buf_len] = '\0'; if (bytes_written) *bytes_written = count; return G_IO_STATUS_NORMAL; } g_assert (from_buf_len - left_len >= from_buf_old_len); /* We converted all the old data. This is fine */ break; case E2BIG: if (from_buf_len == left_len) { /* Nothing was written, add enough space for * at least one character. */ space_in_buf += MAX_CHAR_SIZE; goto reconvert; } break; case EILSEQ: g_set_error (error, G_CONVERT_ERROR, G_CONVERT_ERROR_ILLEGAL_SEQUENCE, _("Invalid byte sequence in conversion input")); if (from_buf_old_len > 0 && from_buf_len == left_len) g_warning ("Illegal sequence due to partial character " "at the end of a previous write.\n"); else wrote_bytes += from_buf_len - left_len - from_buf_old_len; if (bytes_written) *bytes_written = wrote_bytes; channel->partial_write_buf[0] = '\0'; return G_IO_STATUS_ERROR; default: g_set_error (error, G_CONVERT_ERROR, G_CONVERT_ERROR_FAILED, _("Error during conversion: %s"), g_strerror (errnum)); if (from_buf_len >= left_len + from_buf_old_len) wrote_bytes += from_buf_len - left_len - from_buf_old_len; if (bytes_written) *bytes_written = wrote_bytes; channel->partial_write_buf[0] = '\0'; return G_IO_STATUS_ERROR;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -