paraslash 0.7.3
[paraslash.git] / interactive.c
index 91ab1559629725f4b9ae25a3ec167231937bc27d..1376cf1d72739b3f7c9c3218dd96666a5d475812 100644 (file)
@@ -1,8 +1,4 @@
-/*
- * 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. */
 
@@ -49,7 +45,7 @@ static struct i9e_private i9e_private, *i9ep = &i9e_private;
  * 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)
 {
@@ -193,8 +189,6 @@ static char **i9e_completer(const char *text, int start, __a_unused int end)
  *
  * 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)
 {
@@ -262,18 +256,6 @@ static void clear_bottom_line(void)
        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;
@@ -298,14 +280,14 @@ free_line:
        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;
@@ -314,24 +296,29 @@ static int i9e_post_select(__a_unused struct sched *s, __a_unused void *context)
        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)
@@ -373,7 +360,7 @@ out:
        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;
 
@@ -388,7 +375,7 @@ static void i9e_pre_select(struct sched *s, __a_unused void *context)
                        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
@@ -399,7 +386,7 @@ static void i9e_pre_select(struct sched *s, __a_unused void *context)
        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)
@@ -476,8 +463,8 @@ int i9e_open(struct i9e_client_info *ici, struct sched *s)
                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);
 
@@ -560,7 +547,7 @@ __printf_2_3 void i9e_log(int ll, const char* fmt,...)
  * 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;
 
@@ -604,23 +591,21 @@ void i9e_signal_dispatch(int sig_num)
 }
 
 /**
- * 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;
@@ -649,7 +634,7 @@ int i9e_select(int n, fd_set *readfds, fd_set *writefds,
 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);
@@ -660,8 +645,8 @@ int i9e_extract_completions(const char *word, char **string_list,
                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);
        }
@@ -697,7 +682,7 @@ char **i9e_complete_commands(const char *word, struct i9e_completer *completers)
                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);
@@ -766,17 +751,25 @@ int i9e_print_completions(struct i9e_completer *completers)
        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)
@@ -801,3 +794,25 @@ int i9e_print_completions(struct i9e_completer *completers)
        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);
+}