/** * \brief Non-blocking write to a terminal. * * \param client Terminal client state. * \param data Buffer holding characters to write. * \param length The number of characters to write. * \param cont Continuation invoked once the write completes. * * \return SYS_ERR_OK if successful. * TERM_ERR_TX_BUSY if another message is buffered but not yet sent. * TERM_ERR_IO if an I/O error occurred. */ errval_t term_client_write(struct term_client *client, const char *data, size_t length, struct event_closure cont) { errval_t err = SYS_ERR_OK; char *outdata = NULL; assert(client != NULL); assert(data != NULL); assert(length > 0); /* Make a copy of the data, since the output filters might modify them. */ outdata = malloc(length); assert(outdata != NULL); memcpy(outdata, data, length); /* apply output filters */ term_filter_apply(client->output_filters, &outdata, &length); /* try to send characters */ err = client->out_binding->tx_vtbl.characters(client->out_binding, cont, outdata, length); if (err_no(err) == FLOUNDER_ERR_TX_BUSY) { err = err_push(err, TERM_ERR_TX_BUSY); goto out; } else if (err_is_fail(err)) { err = err_push(err, TERM_ERR_IO); goto out; } out: /* free data */ free(outdata); return err; }
/** * \brief Blocking write to a terminal. * * \param client Terminal client state. * \param data Buffer holding characters to write. * \param length The number of characters to write. * \param written Number of characters written. This might be less than length * if an error occurred. * * \return SYS_ERR_OK if successful. * TERM_ERR_IO if an I/O error occurred. * * Dispatches the write waitset until data is sent. */ errval_t term_client_blocking_write(struct term_client *client, const char *data, size_t length, size_t *written) { errval_t err; char *outdata = NULL; assert(data != NULL); assert(length > 0); assert(written != NULL); /* Dispatch the outgoing waitset until we can send characters. */ while (!client->out_binding->can_send(client->out_binding)) { err = event_dispatch(client->write_ws); if (err_is_fail(err)) { return err_push(err, TERM_ERR_IO); } } /* Make a copy of characters, since the output filters might modify them. */ outdata = malloc(length); assert(outdata != NULL); memcpy(outdata, data, length); /* tell user how much we've written (before applying filters) */ *written = length; /* apply output filters */ term_filter_apply(client->output_filters, &outdata, &length); /* send characters */ err = client->out_binding->tx_vtbl.characters(client->out_binding, NOP_CONT, outdata, length); if (err_is_fail(err)) { err = err_push(err, TERM_ERR_IO); goto out; } /* Wait until characters are sent. */ while (!client->out_binding->can_send(client->out_binding)) { err = event_dispatch(client->write_ws); if (err_is_fail(err)) { err = err_push(err, TERM_ERR_IO); goto out; } } out: /* reset amount written if error */ if (err_is_fail(err)) { *written = 0; } /* free data */ free(outdata); return err; }
static errval_t handle_echo(struct term_client *client, char *data, size_t length) { errval_t err = SYS_ERR_OK; char *echodata = NULL; assert(client != NULL); assert(data != NULL); assert(length > 0); /* Dispatch the outgoing waitset until we can send characters */ while (!client->out_binding->can_send(client->out_binding)) { err = event_dispatch(client->write_ws); if (err_is_fail(err)) { return err; } } /* * Make a copy of the data, since the echo filters might modify it and the * modification should not be seen by the application. */ echodata = malloc(length); assert(echodata != NULL); memcpy(echodata, data, length); /* apply echo filters */ term_filter_apply(client->echo_filters, &echodata, &length); /* echo characters */ err = client->out_binding->tx_vtbl.characters(client->out_binding, NOP_CONT, echodata, length); if (err_is_fail(err)) { goto out; } /* Wait until characters echoed. */ while (!client->out_binding->can_send(client->out_binding)) { err = event_dispatch(client->write_ws); if (err_is_fail(err)) { goto out; } } out: /* free data*/ free(echodata); return err; }
static void in_characters_handler(struct terminal_binding *b, char *data, size_t length) { struct term_client *client = b->st; if (client->non_blocking_read) { assert(client->chars_cb != NULL); /* handle triggers */ handle_triggers(client, data, length); /* filter input */ term_filter_apply(client->input_filters, &data, &length); /* call user supplied chars_cb */ client->chars_cb(client->st, data, length); } else { assert(client->readbuf == NULL); client->readbuf = data; client->readbuf_pos = data; client->readbuf_len = length; } }
/** * \brief Blocking read from a terminal. * * \param client Terminal client state. * \param data Buffer to hold read characters. * \param length The number of characters to read. * \param read Number of characters read. This might be less than length if * line_mode is enabled and the end of line was reached or if an * error occurred. * * \return SYS_ERR_OK if successful. * TERM_ERR_IO if an I/O error occurred. * * Dispatches the read if no data is available. */ errval_t term_client_blocking_read(struct term_client *client, char *data, size_t length, size_t *read) { errval_t err; bool eol_reached = false; assert(data != NULL); assert(length > 0); assert(read != NULL); /* * Copy as many characters to the user buffer as he requested but stop if * line mode is enabled and the end of line is reached. */ while ((*read < length) && !(client->line_mode && eol_reached)) { if (client->readbuf == NULL) { /* * Dispatch events on the incoming interface until characters * arrive. */ while (client->readbuf == NULL) { err = event_dispatch(client->read_ws); if (err_is_fail(err)) { return err_push(err, TERM_ERR_IO); } } /* handle echo */ if (client->echo) { err = handle_echo(client, client->readbuf, client->readbuf_len); if (err_is_fail(err)) { return err_push(err, TERM_ERR_IO); } } /* handle triggers */ handle_triggers(client, client->readbuf, client->readbuf_len); /* filter input */ term_filter_apply(client->input_filters, &client->readbuf, &client->readbuf_len); } /* copy data to user supplied buffer */ char *end = client->readbuf + client->readbuf_len; while ((client->readbuf_pos < end) && (*read < length) && !(client->line_mode && eol_reached)) { data[(*read)++] = *client->readbuf_pos; if (client->line_mode && (*client->readbuf_pos == TERM_CLIENT_EOL_CHAR)) { eol_reached = true; } client->readbuf_pos++; } /* free readbuf */ if (client->readbuf_pos == end) { free(client->readbuf); client->readbuf = NULL; client->readbuf_pos = NULL; client->readbuf_len = 0; } } return SYS_ERR_OK; }