1/**
2 * \file
3 * \brief Non-blocking I/O API for terminal client library.
4 */
5
6/*
7 * Copyright (c) 2012, ETH Zurich.
8 * All rights reserved.
9 *
10 * This file is distributed under the terms in the attached LICENSE file.
11 * If you do not find this file, copies can be found by writing to:
12 * ETH Zurich D-INFK, CAB F.78, Universitaetstr. 6, CH-8092 Zurich,
13 * Attn: Systems Group.
14 */
15
16#include <barrelfish/barrelfish.h>
17#include <if/terminal_defs.h>
18#include <if/terminal_config_defs.h>
19#include <term/client/client.h>
20
21#include "filter_priv.h"
22
23#include <assert.h>
24
25/**
26 * \brief Change the waitset used for incoming characters.
27 *
28 * \param client  Terminal client state.
29 * \param read_ws New waitset to use.
30 *
31 * \return SYS_ERR_OK if successful.
32 *         TERM_ERR_CHANGE_WAITSET on error.
33 */
34errval_t term_client_change_read_waitset(struct term_client *client,
35                                         struct waitset *read_ws)
36{
37    errval_t err;
38
39    assert(client != NULL);
40    assert(read_ws != NULL);
41
42    client->read_ws = read_ws;
43    err = client->in_binding->change_waitset(client->in_binding, read_ws);
44    if (err_is_fail(err)) {
45        return err_push(err, TERM_ERR_CHANGE_WAITSET);
46    }
47
48    return SYS_ERR_OK;
49}
50
51/**
52 * \brief Change the waitset used for outgoing characters.
53 *
54 * \param client   Terminal client state.
55 * \param write_ws New waitset to use.
56 *
57 * \return SYS_ERR_OK if successful.
58 *         TERM_ERR_CHANGE_WAITSET on error.
59 */
60errval_t term_client_change_write_waitset(struct term_client *client,
61                                          struct waitset *write_ws)
62{
63    errval_t err;
64
65    assert(client != NULL);
66    assert(write_ws != NULL);
67
68    client->write_ws = write_ws;
69    err = client->out_binding->change_waitset(client->out_binding, write_ws);
70    if (err_is_fail(err)) {
71        return err_push(err, TERM_ERR_CHANGE_WAITSET);
72    }
73
74    return SYS_ERR_OK;
75}
76
77/**
78 * \brief Change the waitset used for configuration messages.
79 *
80 * \param client  Terminal client state.
81 * \param conf_ws New waitset to use.
82 *
83 * \return SYS_ERR_OK if successful.
84 *         TERM_ERR_CHANGE_WAITSET on error.
85 */
86errval_t term_client_change_config_waitset(struct term_client *client,
87                                           struct waitset *conf_ws)
88{
89    errval_t err;
90
91    assert(client != NULL);
92    assert(conf_ws != NULL);
93
94    client->conf_ws = conf_ws;
95    err = client->conf_binding->change_waitset(client->conf_binding, conf_ws);
96    if (err_is_fail(err)) {
97        return err_push(err, TERM_ERR_CHANGE_WAITSET);
98    }
99
100    return SYS_ERR_OK;
101}
102
103/**
104 * \brief Non-blocking write to a terminal.
105 *
106 * \param client  Terminal client state.
107 * \param data    Buffer holding characters to write.
108 * \param length  The number of characters to write.
109 * \param cont    Continuation invoked once the write completes.
110 *
111 * \return SYS_ERR_OK if successful.
112 *         TERM_ERR_TX_BUSY if another message is buffered but not yet sent.
113 *         TERM_ERR_IO if an I/O error occurred.
114 */
115errval_t term_client_write(struct term_client *client, const char *data,
116                           size_t length, struct event_closure cont)
117{
118    errval_t err = SYS_ERR_OK;
119    char *outdata = NULL;
120
121    assert(client != NULL);
122    assert(data != NULL);
123    assert(length > 0);
124
125    /* Make a copy of the data, since the output filters might modify them. */
126    outdata = malloc(length);
127    assert(outdata != NULL);
128    memcpy(outdata, data, length);
129
130    /* apply output filters */
131    term_filter_apply(client->output_filters, &outdata, &length);
132
133    /* try to send characters */
134    err = client->out_binding->tx_vtbl.characters(client->out_binding, cont,
135                                                  outdata, length);
136    if (err_no(err) == FLOUNDER_ERR_TX_BUSY) {
137        err = err_push(err, TERM_ERR_TX_BUSY);
138        goto out;
139    } else if (err_is_fail(err)) {
140        err = err_push(err, TERM_ERR_IO);
141        goto out;
142    }
143
144out:
145    /* free data */
146    free(outdata);
147    return err;
148}
149
150/**
151 * \brief Send a configuration command to the terminal server.
152 *
153 * \param client Terminal client state.
154 * \param opt    Configuration option.
155 * \param arg    Optional argument.
156 * \param cont   Continuation invoked once the configuration message is sent.
157 *
158 * \return SYS_ERR_OK if successful.
159 *         TERM_ERR_TX_BUSY if another message is buffered but not yet sent.
160 *         TERM_ERR_UNKNOWN_CONFIG_OPT if opt is unknown.
161 */
162errval_t term_client_config(struct term_client *client,
163                            terminal_config_option_t opt, char *arg,
164                            struct event_closure cont)
165{
166    assert(!"NYI");
167    return TERM_ERR_UNKNOWN_CONFIG_OPT;
168}
169
170/**
171 * \brief Set an error handler, called when an asynchronous error occurs.
172 *
173 * \param client Terminal client state.
174 * \param err_cb Error handler.
175 */
176void term_client_set_err_handler(struct term_client *client,
177                                 term_async_err_handler_fn err_cb)
178{
179    assert(client != NULL);
180    assert(err_cb != NULL);
181
182    client->err_cb = err_cb;
183}
184
185/**
186 * \brief Set handler that is called when new characters arrive.
187 *
188 * \param client   Terminal client state.
189 * \param chars_cb Characters handler.
190 */
191void term_client_set_chars_handler(struct term_client *client,
192                                   term_characters_handler_fn *chars_cb)
193{
194    assert(client != NULL);
195    assert(chars_cb != NULL);
196
197    client->chars_cb = chars_cb;
198    client->non_blocking_read = true;
199}
200