]> git.pond.sub.org Git - empserver/blobdiff - src/client/play.c
client: Add a missing #include <string.h>
[empserver] / src / client / play.c
index ad7028c78c51dc01517c30d7122a1754049172c5..4f7757173e955f9af5bcde3c8e7534e99c07921b 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *  Empire - A multi-player, client/server Internet based war game.
- *  Copyright (C) 1986-2015, Dave Pare, Jeff Bailey, Thomas Ruschak,
+ *  Copyright (C) 1986-2017, Dave Pare, Jeff Bailey, Thomas Ruschak,
  *                Ken Stevens, Steve McClure, Markus Armbruster
  *
  *  Empire is free software: you can redistribute it and/or modify
@@ -29,6 +29,7 @@
  *  Known contributors to this file:
  *     Markus Armbruster, 2007-2017
  *     Ron Koenderink, 2007-2009
+ *     Martin Haukeli, 2015
  */
 
 #include <config.h>
@@ -38,6 +39,7 @@
 #include <signal.h>
 #include <stdio.h>
 #include <stdlib.h>
+#include <string.h>
 #ifdef _WIN32
 #include <process.h>
 #include <sys/socket.h>
 #include "secure.h"
 
 #ifdef HAVE_LIBREADLINE
-#  if defined(HAVE_READLINE_READLINE_H)
-#    include <readline/readline.h>
-#  elif defined(HAVE_READLINE_H)
-#    include <readline.h>
-#  else /* !defined(HAVE_READLINE_H) */
-extern char *readline ();
-#  endif /* !defined(HAVE_READLINE_H) */
-#endif /* HAVE_LIBREADLINE */
-
-#ifdef HAVE_READLINE_HISTORY
-#  if defined(HAVE_READLINE_HISTORY_H)
-#    include <readline/history.h>
-#  elif defined(HAVE_HISTORY_H)
-#    include <history.h>
-#  else /* !defined(HAVE_HISTORY_H) */
-extern void add_history ();
-extern int write_history ();
-extern int read_history ();
-#  endif /* !defined(HAVE_HISTORY_H) */
-#endif /* HAVE_READLINE_HISTORY */
+#include <readline/readline.h>
+#include <readline/history.h>
+#endif
 
 #define EOF_COOKIE "ctld\n"
 #define INTR_COOKIE "aborted\n"
@@ -348,10 +333,10 @@ recv_output(int sock)
      * simple state machine.
      * Initial state is SCANNING_ID.
      * In state SCANNING_ID, buffer the character.  If it's a space,
-     * decode the id that has been buffered, and enter state BUFFERING
+     * decode the ID that has been buffered, and enter state BUFFERING
      * or COPYING depending on its value.
      * In state BUFFERING, buffer the character.  If it's newline,
-     * pass id and buffered text to servercmd(), then enter state
+     * pass ID and buffered text to servercmd(), then enter state
      * SCANNING_ID.
      * In state COPYING, pass the character to outch().  If it's
      * newline, enter state SCANNING_ID.
@@ -398,7 +383,7 @@ recv_output(int sock)
                state = BUFFERING;
                break;
            default:
-               /* unknown or unexpected id, treat like C_DATA */
+               /* unknown or unexpected ID, treat like C_DATA */
            case C_DATA:
                state = COPYING;
                break;
@@ -436,8 +421,8 @@ recv_output(int sock)
     return n;
 }
 
-char *history_file = NULL;
 #ifdef HAVE_LIBREADLINE
+static int use_readline;
 static char *input_from_rl;
 static int has_rl_input;
 
@@ -446,11 +431,34 @@ input_handler(char *line)
 {
     input_from_rl = line;
     has_rl_input = 1;
-    rl_already_prompted = 1;
-#ifdef HAVE_READLINE_HISTORY
     if (line && *line)
        add_history(line);
-#endif /* HAVE_READLINE_HISTORY */
+}
+
+static int
+ring_from_rl(struct ring *inbuf)
+{
+    size_t len;
+    int n;
+
+    assert(has_rl_input && input_from_rl);
+
+    len = strlen(input_from_rl);
+    n = ring_space(inbuf);
+    assert(n);
+
+    if (len >= (size_t)n) {
+       ring_putm(inbuf, input_from_rl, n);
+       memmove(input_from_rl, input_from_rl + n, len - n + 1);
+    } else {
+       ring_putm(inbuf, input_from_rl, len);
+       ring_putc(inbuf, '\n');
+       free(input_from_rl);
+       has_rl_input = 0;
+       n = len + 1;
+    }
+
+    return n;
 }
 #endif /* HAVE_LIBREADLINE */
 
@@ -463,28 +471,15 @@ recv_input(int fd, struct ring *inbuf)
 {
     int n;
     int res = 1;
-#ifdef HAVE_LIBREADLINE
-    size_t len;
 
-    if (fd == 0) {
+#ifdef HAVE_LIBREADLINE
+    if (fd == 0 && use_readline) {
        if (!has_rl_input)
            rl_callback_read_char();
        if (!has_rl_input)
            return 1;
        if (input_from_rl) {
-           len = strlen(input_from_rl);
-           n = ring_space(inbuf);
-           assert(n);
-           if (len >= (size_t)n) {
-               ring_putm(inbuf, input_from_rl, n);
-               memmove(input_from_rl, input_from_rl + n, len - n + 1);
-           } else {
-               ring_putm(inbuf, input_from_rl, len);
-               ring_putc(inbuf, '\n');
-               free(input_from_rl);
-               has_rl_input = 0;
-               n = len + 1;
-           }
+           n = ring_from_rl(inbuf);
        } else
            n = 0;
     } else
@@ -494,7 +489,7 @@ recv_input(int fd, struct ring *inbuf)
        return -1;
     if (n == 0) {
        /*
-        * Can't put EOF cookie into INBUF here, it may not fit.
+        * Can't put EOF cookie into @inbuf here, it may not fit.
         * Leave it to caller.
         */
        res = 0;
@@ -525,6 +520,11 @@ send_input(int fd, struct ring *inbuf)
            putc(ch, auxfp);
     }
 
+#ifdef HAVE_LIBREADLINE
+    if (fd == 0 && use_readline && has_rl_input && input_from_rl)
+       ring_from_rl(inbuf);
+#endif
+
     return res;
 }
 
@@ -536,17 +536,18 @@ intr(int sig)
 
 /*
  * Play on @sock.
+ * @history_file is the name of the history file, or null.
  * The session must be in the playing phase.
  * Return 0 when the session ended, -1 on error.
  */
 int
-play(int sock)
+play(int sock, char *history_file)
 {
     /*
-     * Player input flows from INPUT_FD through recv_input() into ring
-     * buffer INBUF, which drains into SOCK.  This must not block.
-     * Server output flows from SOCK into recv_output().  Reading SOCK
-     * must not block.
+     * Player input flows from @input_fd through recv_input() into
+     * ring buffer @inbuf, which drains into @sock.  This must not
+     * block.  Server output flows from @sock into recv_output().
+     * Reading @sock must not block.
      */
     struct sigaction sa;
     struct ring inbuf;         /* input buffer, draining to SOCK */
@@ -564,12 +565,15 @@ play(int sock)
     sa.sa_handler = SIG_IGN;
     sigaction(SIGPIPE, &sa, NULL);
 #ifdef HAVE_LIBREADLINE
-#ifdef HAVE_READLINE_HISTORY
-    if (history_file)
-       read_history(history_file);
-#endif /* HAVE_READLINE_HISTORY */
-    rl_bind_key('\t', rl_insert);  /* Disable tab completion */
-    rl_callback_handler_install("", input_handler);
+    if (isatty(0)) {
+       use_readline = 1;
+       rl_already_prompted = 1;
+       rl_readline_name = "Empire";
+       if (history_file)
+           read_history(history_file);
+       rl_bind_key('\t', rl_insert);  /* Disable tab completion */
+       rl_callback_handler_install("", input_handler);
+    }
 #endif /* HAVE_LIBREADLINE */
 
     ring_init(&inbuf);
@@ -665,19 +669,40 @@ play(int sock)
                break;
            }
            if (n == 0) {
-#ifdef HAVE_LIBREADLINE
-#ifdef HAVE_READLINE_HISTORY
-               if (history_file)
-                   write_history(history_file);
-#endif /* HAVE_READLINE_HISTORY */
-#endif /* HAVE_LIBREADLINE */
                ret = 0;
                break;
            }
        }
     }
+
 #ifdef HAVE_LIBREADLINE
-    rl_callback_handler_remove();
+    if (use_readline) {
+       rl_callback_handler_remove();
+       if (history_file)
+           write_history(history_file);
+    }
 #endif
     return ret;
 }
+
+void
+prompt(int code, char *prompt, char *teles)
+{
+    char pr[1024];
+
+    snprintf(pr, sizeof(pr), "%s%s", teles, prompt);
+#ifdef HAVE_LIBREADLINE
+    if (use_readline) {
+       rl_set_prompt(pr);
+       rl_forced_update_display();
+    } else
+#endif /* HAVE_LIBREADLINE */
+    {
+       printf("%s", pr);
+       fflush(stdout);
+    }
+    if (auxfp) {
+       fprintf(auxfp, "%s%s", teles, prompt);
+       fflush(auxfp);
+    }
+}