-/*
- * Copyright (C) 2011 Andre Noll <maan@tuebingen.mpg.de>
- *
- * Licensed under the GPL v2. For licencing details see COPYING.
- */
+/* Copyright (C) 2011 Andre Noll <maan@tuebingen.mpg.de>, see file COPYING. */
/** \file interactive.c Readline abstraction for interactive sessions. */
* running.
*
* \return A negative return value of zero means the i9e task terminated. Only
- * in this case it is safe to call ie9_close().
+ * in this case it is safe to call i9e_close().
*/
int i9e_get_error(void)
{
*
* This function attaches the i9e input queue to an output queue of \a
* producer.
- *
- * \return Standard.
*/
void i9e_attach_to_stdout(struct btr_node *producer)
{
rl_callback_handler_remove();
if (hf)
write_history(hf);
+ clear_history();
wipe_bottom_line();
fcntl(i9ep->ici->fds[0], F_SETFL, i9ep->fd_flags[0]);
fcntl(i9ep->ici->fds[1], F_SETFL, i9ep->fd_flags[1]);
rl_point = point;
}
-static bool input_available(void)
-{
- fd_set rfds;
- struct timeval tv = {0, 0};
- int ret;
-
- FD_ZERO(&rfds);
- FD_SET(i9ep->ici->fds[0], &rfds);
- ret = para_select(1, &rfds, NULL, &tv);
- return ret > 0;
-}
-
static void i9e_line_handler(char *line)
{
int ret;
free(line);
}
-static int i9e_post_select(__a_unused struct sched *s, __a_unused void *context)
+static int i9e_post_monitor(__a_unused struct sched *s, __a_unused void *context)
{
int ret;
struct i9e_client_info *ici = i9ep->ici;
char *buf;
size_t sz, consumed = 0;
- ret = -E_I9E_EOF;
+ ret = -E_EOF;
if (i9ep->input_eof)
goto rm_btrn;
ret = -E_I9E_TERM_RQ;
ret = 0;
if (i9ep->caught_sigint)
goto rm_btrn;
- while (input_available()) {
+ while (read_ok(i9ep->ici->fds[0]) > 0) {
if (i9ep->stdout_btrn) {
- unsigned len = i9ep->key_sequence_length;
- assert(len < sizeof(i9ep->key_sequence) - 1);
- buf = i9ep->key_sequence + len;
- ret = read(i9ep->ici->fds[0], buf, 1);
- if (ret < 0) {
- ret = -ERRNO_TO_PARA_ERROR(errno);
- goto rm_btrn;
+ while (i9ep->key_sequence_length < sizeof(i9ep->key_sequence) - 1) {
+ buf = i9ep->key_sequence + i9ep->key_sequence_length;
+ ret = read(i9ep->ici->fds[0], buf, 1);
+ if (ret < 0) {
+ ret = -ERRNO_TO_PARA_ERROR(errno);
+ goto rm_btrn;
+ }
+ if (ret == 0) {
+ ret = -E_EOF;
+ goto rm_btrn;
+ }
+ buf[1] = '\0';
+ i9ep->key_sequence_length++;
+ rl_stuff_char((int)(unsigned char)*buf);
+ rl_callback_read_char();
+ if (read_ok(i9ep->ici->fds[0]) <= 0)
+ break;
}
- ret = -E_I9E_EOF;
- if (ret == 0)
- goto rm_btrn;
- buf[1] = '\0';
- i9ep->key_sequence_length++;
- rl_stuff_char((int)(unsigned char)*buf);
- }
- rl_callback_read_char();
+ i9ep->key_sequence_length = 0;
+ } else
+ rl_callback_read_char();
ret = 0;
}
if (!i9ep->stdout_btrn)
return ret;
}
-static void i9e_pre_select(struct sched *s, __a_unused void *context)
+static void i9e_pre_monitor(struct sched *s, __a_unused void *context)
{
int ret;
return;
}
if (ret > 0)
- para_fd_set(i9ep->ici->fds[1], &s->wfds, &s->max_fileno);
+ sched_monitor_writefd(i9ep->ici->fds[1], s);
}
/*
* fd[0] might have been reset to blocking mode if our job was moved to
if (ret < 0)
PARA_WARNING_LOG("set to nonblock failed: (fd0 %d, %s)\n",
i9ep->ici->fds[0], para_strerror(-ret));
- para_fd_set(i9ep->ici->fds[0], &s->rfds, &s->max_fileno);
+ sched_monitor_readfd(i9ep->ici->fds[0], s);
}
static void update_winsize(void)
return ret;
i9ep->task = task_register(&(struct task_info) {
.name = "i9e",
- .pre_select = i9e_pre_select,
- .post_select = i9e_post_select,
+ .pre_monitor = i9e_pre_monitor,
+ .post_monitor = i9e_post_monitor,
.context = i9ep,
}, s);
* the given text. If the length of this text exceeds the width of the
* terminal, the text is shortened by leaving out a part in the middle.
*/
-void ie9_print_status_bar(char *buf, unsigned len)
+void i9e_print_status_bar(char *buf, unsigned len)
{
size_t x = i9ep->num_columns, y = (x - 4) / 2;
}
/**
- * Wrapper for select(2) which does not restart on interrupts.
+ * Wrapper for poll(2) which handles EINTR and returns paraslash error codes.
*
- * \param n \sa \ref para_select().
- * \param readfds \sa \ref para_select().
- * \param writefds \sa \ref para_select().
- * \param timeout_tv \sa \ref para_select().
+ * \param fds See poll(2).
+ * \param nfds See poll(2).
+ * \param timeout See poll(2).
*
- * \return \sa \ref para_select().
+ * \return See poll(2).
*
- * The only difference between this function and \ref para_select() is that
- * \ref i9e_select() returns zero if the select call returned \p EINTR.
+ * The only difference between this function and \ref xpoll() is that \ref
+ * i9e_poll() returns zero if the system call was interrupted while xpoll()
+ * restarts the system call in this case.
*/
-int i9e_select(int n, fd_set *readfds, fd_set *writefds,
- struct timeval *timeout_tv)
+int i9e_poll(struct pollfd *fds, nfds_t nfds, int timeout)
{
- int ret = select(n, readfds, writefds, NULL, timeout_tv);
-
+ int ret = poll(fds, nfds, timeout);
if (ret < 0) {
if (errno == EINTR)
ret = 0;
int i9e_extract_completions(const char *word, char **string_list,
char ***result)
{
- char **matches = para_malloc(sizeof(char *));
+ char **matches = alloc(sizeof(char *));
int match_count = 0, matches_len = 1;
char **p;
int len = strlen(word);
match_count++;
if (match_count >= matches_len) {
matches_len *= 2;
- matches = para_realloc(matches,
- matches_len * sizeof(char *));
+ matches = arr_realloc(matches, matches_len,
+ sizeof(char *));
}
matches[match_count - 1] = para_strdup(*p);
}
if (is_prefix(word, cmd, len))
match_count++;
}
- matches = para_malloc((match_count + 1) * sizeof(*matches));
+ matches = arr_alloc(match_count + 1, sizeof(*matches));
for (i = 0, match_count = 0; (cmd = completers[i].name); i++)
if (is_prefix(word, cmd, len))
matches[match_count++] = para_strdup(cmd);
ci.argc = create_argv(ci.buffer, " ", &ci.argv);
ci.word_num = compute_word_num(ci.buffer, " ", ci.point);
+ /* determine the current word to complete */
end = ci.buffer + ci.point;
+
+ if (*end == ' ') {
+ if (ci.point == 0 || ci.buffer[ci.point - 1] == ' ') {
+ ci.word = para_strdup(NULL);
+ goto create_matches;
+ } else /* The cursor is positioned right after a word */
+ end--;
+ }
for (p = end; p > ci.buffer && *p != ' '; p--)
; /* nothing */
if (*p == ' ')
p++;
-
n = end - p + 1;
- ci.word = para_malloc(n + 1);
+ ci.word = alloc(n + 1);
strncpy(ci.word, p, n);
ci.word[n] = '\0';
-
+create_matches:
PARA_DEBUG_LOG("line: %s, point: %d (%c), wordnum: %d, word: %s\n",
ci.buffer, ci.point, ci.buffer[ci.point], ci.word_num, ci.word);
if (ci.word_num == 0)
free(ci.word);
return ret;
}
+
+/**
+ * Complete on severity strings.
+ *
+ * \param ci See struct \ref i9e_completer.
+ * \param cr See struct \ref i9e_completer.
+ *
+ * This is used by para_client and para_audioc which need the same completion
+ * primitive for the ll server/audiod command. Both define their own completer
+ * which is implemented as a trivial wrapper that calls this function.
+ */
+void i9e_ll_completer(struct i9e_completion_info *ci,
+ struct i9e_completion_result *cr)
+{
+ char *sev[] = {SEVERITIES, NULL};
+
+ if (ci->word_num != 1) {
+ cr->matches = NULL;
+ return;
+ }
+ i9e_extract_completions(ci->word, sev, &cr->matches);
+}