diff --git a/demo/mtest_opponent.c b/demo/mtest_opponent.c
index edbecc0c1..25d9b5b90 100644
--- a/demo/mtest_opponent.c
+++ b/demo/mtest_opponent.c
@@ -6,16 +6,56 @@
 #define LTM_MTEST_RAND_SEED  23
 #endif
 
-static void draw(const mp_int *a)
+#define DRAW(a) do{ ndraw(&(a), #a); }while(0)
+
+/*
+   Get tokens. It is just a very(!) simple fgets(3) that does not keep line endings.
+
+   Implementation follows along "man 3 fgets", some of which is quoted.
+ */
+static int s_mp_get_token(char *s, int size, FILE *stream)
 {
-   ndraw(a, "");
-}
+   char *s_bar = s;
+   int c;
+   bool eol_hit = false;
 
-#define FGETS(str, size, stream) \
-   { \
-      char *ret = fgets(str, size, stream); \
-      if (!ret) { fprintf(stderr, "\n%d: fgets failed\n", __LINE__); goto LBL_ERR; } \
+   /* "fgets [...] reads in at most one less than size characters from stream"  */
+   while (--size)  {
+      /* "Reading stops after an EOF or a newline." We stop only for EOF here */
+      if ((c = fgetc(stream)) == EOF) {
+         /* "Returns [...] NULL on error or when end of file occurs while no characters have been read" */
+         if ((s_bar == s) || (ferror(stream) != 0)) {
+            return -1;
+         }
+         break;
+      }
+      /* Ignore line-breaks but keep reading to get them out of the stream-buffer */
+      if ((c == '\n') || (c == '\r')) {
+         eol_hit = true;
+         continue;
+      }
+      /* Stop reading after linebreak */
+      if (eol_hit) {
+         /* We already read the character after the linebreak, put it back */
+         ungetc(c, stream);
+         break;
+      }
+      *s_bar++ = c;
    }
+   if (size == 0) return -2;
+   /* "A terminating null byte ('\0') is stored after the last character in the buffer" */
+   *s_bar = '\0';
+   return 0;
+}
+
+#define TMP_(r,l) r ## _ ## l
+#define TMP(r,l) TMP_(r,l)
+
+#define GET_TOKEN(str, stream) \
+   do { \
+      int TMP(ret,__LINE__) = s_mp_get_token((str), sizeof(str), (stream)); \
+      if (TMP(ret,__LINE__) < 0) { fprintf(stderr, "\n%d: s_mp_get_token failed with error %d\n", __LINE__, TMP(ret,__LINE__)); goto LBL_ERR; } \
+   } while(0)
 
 static int mtest_opponent(void)
 {
@@ -76,34 +116,33 @@ static int mtest_opponent(void)
       printf("%4lu/%4lu/%4lu/%4lu/%4lu/%4lu/%4lu/%4lu/%4lu/%4lu/%4lu/%4lu/%4lu/%4lu/%4lu ",
              add_n, sub_n, mul_n, div_n, sqr_n, mul2d_n, div2d_n, gcd_n, lcm_n,
              expt_n, inv_n, div2_n, mul2_n, add_d_n, sub_d_n);
-      FGETS(cmd, 4095, stdin);
-      cmd[strlen(cmd) - 1u] = '\0';
+      GET_TOKEN(cmd, stdin);
       printf("%-6s ]\r", cmd);
       fflush(stdout);
       if (strcmp(cmd, "mul2d") == 0) {
          ++mul2d_n;
-         FGETS(buf, 4095, stdin);
+         GET_TOKEN(buf, stdin);
          DO(mp_read_radix(&a, buf, 64));
-         FGETS(buf, 4095, stdin);
+         GET_TOKEN(buf, stdin);
          sscanf(buf, "%u", &rr);
-         FGETS(buf, 4095, stdin);
+         GET_TOKEN(buf, stdin);
          DO(mp_read_radix(&b, buf, 64));
 
          DO(mp_mul_2d(&a, (int)rr, &a));
          a.sign = b.sign;
          if (mp_cmp(&a, &b) != MP_EQ) {
             printf("mul2d failed, rr == %u\n", rr);
-            draw(&a);
-            draw(&b);
+            DRAW(a);
+            DRAW(b);
             goto LBL_ERR;
          }
       } else if (strcmp(cmd, "div2d") == 0) {
          ++div2d_n;
-         FGETS(buf, 4095, stdin);
+         GET_TOKEN(buf, stdin);
          DO(mp_read_radix(&a, buf, 64));
-         FGETS(buf, 4095, stdin);
+         GET_TOKEN(buf, stdin);
          sscanf(buf, "%u", &rr);
-         FGETS(buf, 4095, stdin);
+         GET_TOKEN(buf, stdin);
          DO(mp_read_radix(&b, buf, 64));
 
          DO(mp_div_2d(&a, (int)rr, &a, &e));
@@ -113,26 +152,26 @@ static int mtest_opponent(void)
          }
          if (mp_cmp(&a, &b) != MP_EQ) {
             printf("div2d failed, rr == %u\n", rr);
-            draw(&a);
-            draw(&b);
+            DRAW(a);
+            DRAW(b);
             goto LBL_ERR;
          }
       } else if (strcmp(cmd, "add") == 0) {
          ++add_n;
-         FGETS(buf, 4095, stdin);
+         GET_TOKEN(buf, stdin);
          DO(mp_read_radix(&a, buf, 64));
-         FGETS(buf, 4095, stdin);
+         GET_TOKEN(buf, stdin);
          DO(mp_read_radix(&b, buf, 64));
-         FGETS(buf, 4095, stdin);
+         GET_TOKEN(buf, stdin);
          DO(mp_read_radix(&c, buf, 64));
          DO(mp_copy(&a, &d));
          DO(mp_add(&d, &b, &d));
          if (mp_cmp(&c, &d) != MP_EQ) {
             printf("add %lu failure!\n", add_n);
-            draw(&a);
-            draw(&b);
-            draw(&c);
-            draw(&d);
+            DRAW(a);
+            DRAW(b);
+            DRAW(c);
+            DRAW(d);
             goto LBL_ERR;
          }
 
@@ -144,8 +183,8 @@ static int mtest_opponent(void)
          DO(mp_from_sbin(&d, (uint8_t *) cmd, (size_t)rr));
          if (mp_cmp(&c, &d) != MP_EQ) {
             printf("mp_signed_bin failure!\n");
-            draw(&c);
-            draw(&d);
+            DRAW(c);
+            DRAW(d);
             goto LBL_ERR;
          }
 
@@ -155,226 +194,226 @@ static int mtest_opponent(void)
          DO(mp_from_ubin(&d, (uint8_t *) cmd, (size_t)rr));
          if (mp_cmp_mag(&c, &d) != MP_EQ) {
             printf("mp_unsigned_bin failure!\n");
-            draw(&c);
-            draw(&d);
+            DRAW(c);
+            DRAW(d);
             goto LBL_ERR;
          }
 
       } else if (strcmp(cmd, "sub") == 0) {
          ++sub_n;
-         FGETS(buf, 4095, stdin);
+         GET_TOKEN(buf, stdin);
          DO(mp_read_radix(&a, buf, 64));
-         FGETS(buf, 4095, stdin);
+         GET_TOKEN(buf, stdin);
          DO(mp_read_radix(&b, buf, 64));
-         FGETS(buf, 4095, stdin);
+         GET_TOKEN(buf, stdin);
          DO(mp_read_radix(&c, buf, 64));
          DO(mp_copy(&a, &d));
          DO(mp_sub(&d, &b, &d));
          if (mp_cmp(&c, &d) != MP_EQ) {
             printf("sub %lu failure!\n", sub_n);
-            draw(&a);
-            draw(&b);
-            draw(&c);
-            draw(&d);
+            DRAW(a);
+            DRAW(b);
+            DRAW(c);
+            DRAW(d);
             goto LBL_ERR;
          }
       } else if (strcmp(cmd, "mul") == 0) {
          ++mul_n;
-         FGETS(buf, 4095, stdin);
+         GET_TOKEN(buf, stdin);
          DO(mp_read_radix(&a, buf, 64));
-         FGETS(buf, 4095, stdin);
+         GET_TOKEN(buf, stdin);
          DO(mp_read_radix(&b, buf, 64));
-         FGETS(buf, 4095, stdin);
+         GET_TOKEN(buf, stdin);
          DO(mp_read_radix(&c, buf, 64));
          DO(mp_copy(&a, &d));
          DO(mp_mul(&d, &b, &d));
          if (mp_cmp(&c, &d) != MP_EQ) {
             printf("mul %lu failure!\n", mul_n);
-            draw(&a);
-            draw(&b);
-            draw(&c);
-            draw(&d);
+            DRAW(a);
+            DRAW(b);
+            DRAW(c);
+            DRAW(d);
             goto LBL_ERR;
          }
       } else if (strcmp(cmd, "div") == 0) {
          ++div_n;
-         FGETS(buf, 4095, stdin);
+         GET_TOKEN(buf, stdin);
          DO(mp_read_radix(&a, buf, 64));
-         FGETS(buf, 4095, stdin);
+         GET_TOKEN(buf, stdin);
          DO(mp_read_radix(&b, buf, 64));
-         FGETS(buf, 4095, stdin);
+         GET_TOKEN(buf, stdin);
          DO(mp_read_radix(&c, buf, 64));
-         FGETS(buf, 4095, stdin);
+         GET_TOKEN(buf, stdin);
          DO(mp_read_radix(&d, buf, 64));
 
          DO(mp_div(&a, &b, &e, &f));
          if ((mp_cmp(&c, &e) != MP_EQ) || (mp_cmp(&d, &f) != MP_EQ)) {
             printf("div %lu %d, %d, failure!\n", div_n, mp_cmp(&c, &e),
                    mp_cmp(&d, &f));
-            draw(&a);
-            draw(&b);
-            draw(&c);
-            draw(&d);
-            draw(&e);
-            draw(&f);
+            DRAW(a);
+            DRAW(b);
+            DRAW(c);
+            DRAW(d);
+            DRAW(e);
+            DRAW(f);
             goto LBL_ERR;
          }
 
       } else if (strcmp(cmd, "sqr") == 0) {
          ++sqr_n;
-         FGETS(buf, 4095, stdin);
+         GET_TOKEN(buf, stdin);
          DO(mp_read_radix(&a, buf, 64));
-         FGETS(buf, 4095, stdin);
+         GET_TOKEN(buf, stdin);
          DO(mp_read_radix(&b, buf, 64));
          DO(mp_copy(&a, &c));
          DO(mp_sqr(&c, &c));
          if (mp_cmp(&b, &c) != MP_EQ) {
             printf("sqr %lu failure!\n", sqr_n);
-            draw(&a);
-            draw(&b);
-            draw(&c);
+            DRAW(a);
+            DRAW(b);
+            DRAW(c);
             goto LBL_ERR;
          }
       } else if (strcmp(cmd, "gcd") == 0) {
          ++gcd_n;
-         FGETS(buf, 4095, stdin);
+         GET_TOKEN(buf, stdin);
          DO(mp_read_radix(&a, buf, 64));
-         FGETS(buf, 4095, stdin);
+         GET_TOKEN(buf, stdin);
          DO(mp_read_radix(&b, buf, 64));
-         FGETS(buf, 4095, stdin);
+         GET_TOKEN(buf, stdin);
          DO(mp_read_radix(&c, buf, 64));
          DO(mp_copy(&a, &d));
          DO(mp_gcd(&d, &b, &d));
          d.sign = c.sign;
          if (mp_cmp(&c, &d) != MP_EQ) {
             printf("gcd %lu failure!\n", gcd_n);
-            draw(&a);
-            draw(&b);
-            draw(&c);
-            draw(&d);
+            DRAW(a);
+            DRAW(b);
+            DRAW(c);
+            DRAW(d);
             goto LBL_ERR;
          }
       } else if (strcmp(cmd, "lcm") == 0) {
          ++lcm_n;
-         FGETS(buf, 4095, stdin);
+         GET_TOKEN(buf, stdin);
          DO(mp_read_radix(&a, buf, 64));
-         FGETS(buf, 4095, stdin);
+         GET_TOKEN(buf, stdin);
          DO(mp_read_radix(&b, buf, 64));
-         FGETS(buf, 4095, stdin);
+         GET_TOKEN(buf, stdin);
          DO(mp_read_radix(&c, buf, 64));
          DO(mp_copy(&a, &d));
          DO(mp_lcm(&d, &b, &d));
          d.sign = c.sign;
          if (mp_cmp(&c, &d) != MP_EQ) {
             printf("lcm %lu failure!\n", lcm_n);
-            draw(&a);
-            draw(&b);
-            draw(&c);
-            draw(&d);
+            DRAW(a);
+            DRAW(b);
+            DRAW(c);
+            DRAW(d);
             goto LBL_ERR;
          }
       } else if (strcmp(cmd, "expt") == 0) {
          ++expt_n;
-         FGETS(buf, 4095, stdin);
+         GET_TOKEN(buf, stdin);
          DO(mp_read_radix(&a, buf, 64));
-         FGETS(buf, 4095, stdin);
+         GET_TOKEN(buf, stdin);
          DO(mp_read_radix(&b, buf, 64));
-         FGETS(buf, 4095, stdin);
+         GET_TOKEN(buf, stdin);
          DO(mp_read_radix(&c, buf, 64));
-         FGETS(buf, 4095, stdin);
+         GET_TOKEN(buf, stdin);
          DO(mp_read_radix(&d, buf, 64));
          DO(mp_copy(&a, &e));
          DO(mp_exptmod(&e, &b, &c, &e));
          if (mp_cmp(&d, &e) != MP_EQ) {
             printf("expt %lu failure!\n", expt_n);
-            draw(&a);
-            draw(&b);
-            draw(&c);
-            draw(&d);
-            draw(&e);
+            DRAW(a);
+            DRAW(b);
+            DRAW(c);
+            DRAW(d);
+            DRAW(e);
             goto LBL_ERR;
          }
       } else if (strcmp(cmd, "invmod") == 0) {
          ++inv_n;
-         FGETS(buf, 4095, stdin);
+         GET_TOKEN(buf, stdin);
          DO(mp_read_radix(&a, buf, 64));
-         FGETS(buf, 4095, stdin);
+         GET_TOKEN(buf, stdin);
          DO(mp_read_radix(&b, buf, 64));
-         FGETS(buf, 4095, stdin);
+         GET_TOKEN(buf, stdin);
          DO(mp_read_radix(&c, buf, 64));
          DO(mp_invmod(&a, &b, &d));
          DO(mp_mulmod(&d, &a, &b, &e));
          if (mp_cmp_d(&e, 1u) != MP_EQ) {
             printf("inv [wrong value from MPI?!] failure\n");
-            draw(&a);
-            draw(&b);
-            draw(&c);
-            draw(&d);
-            draw(&e);
+            DRAW(a);
+            DRAW(b);
+            DRAW(c);
+            DRAW(d);
+            DRAW(e);
             DO(mp_gcd(&a, &b, &e));
-            draw(&e);
+            DRAW(e);
             goto LBL_ERR;
          }
 
       } else if (strcmp(cmd, "div2") == 0) {
          ++div2_n;
-         FGETS(buf, 4095, stdin);
+         GET_TOKEN(buf, stdin);
          DO(mp_read_radix(&a, buf, 64));
-         FGETS(buf, 4095, stdin);
+         GET_TOKEN(buf, stdin);
          DO(mp_read_radix(&b, buf, 64));
          DO(mp_div_2(&a, &c));
          if (mp_cmp(&c, &b) != MP_EQ) {
             printf("div_2 %lu failure\n", div2_n);
-            draw(&a);
-            draw(&b);
-            draw(&c);
+            DRAW(a);
+            DRAW(b);
+            DRAW(c);
             goto LBL_ERR;
          }
       } else if (strcmp(cmd, "mul2") == 0) {
          ++mul2_n;
-         FGETS(buf, 4095, stdin);
+         GET_TOKEN(buf, stdin);
          DO(mp_read_radix(&a, buf, 64));
-         FGETS(buf, 4095, stdin);
+         GET_TOKEN(buf, stdin);
          DO(mp_read_radix(&b, buf, 64));
          DO(mp_mul_2(&a, &c));
          if (mp_cmp(&c, &b) != MP_EQ) {
             printf("mul_2 %lu failure\n", mul2_n);
-            draw(&a);
-            draw(&b);
-            draw(&c);
+            DRAW(a);
+            DRAW(b);
+            DRAW(c);
             goto LBL_ERR;
          }
       } else if (strcmp(cmd, "add_d") == 0) {
          ++add_d_n;
-         FGETS(buf, 4095, stdin);
+         GET_TOKEN(buf, stdin);
          DO(mp_read_radix(&a, buf, 64));
-         FGETS(buf, 4095, stdin);
+         GET_TOKEN(buf, stdin);
          sscanf(buf, "%d", &ix);
-         FGETS(buf, 4095, stdin);
+         GET_TOKEN(buf, stdin);
          DO(mp_read_radix(&b, buf, 64));
          DO(mp_add_d(&a, (mp_digit)ix, &c));
          if (mp_cmp(&b, &c) != MP_EQ) {
             printf("add_d %lu failure\n", add_d_n);
-            draw(&a);
-            draw(&b);
-            draw(&c);
+            DRAW(a);
+            DRAW(b);
+            DRAW(c);
             printf("d == %d\n", ix);
             goto LBL_ERR;
          }
       } else if (strcmp(cmd, "sub_d") == 0) {
          ++sub_d_n;
-         FGETS(buf, 4095, stdin);
+         GET_TOKEN(buf, stdin);
          DO(mp_read_radix(&a, buf, 64));
-         FGETS(buf, 4095, stdin);
+         GET_TOKEN(buf, stdin);
          sscanf(buf, "%d", &ix);
-         FGETS(buf, 4095, stdin);
+         GET_TOKEN(buf, stdin);
          DO(mp_read_radix(&b, buf, 64));
          DO(mp_sub_d(&a, (mp_digit)ix, &c));
          if (mp_cmp(&b, &c) != MP_EQ) {
             printf("sub_d %lu failure\n", sub_d_n);
-            draw(&a);
-            draw(&b);
-            draw(&c);
+            DRAW(a);
+            DRAW(b);
+            DRAW(c);
             printf("d == %d\n", ix);
             goto LBL_ERR;
          }
diff --git a/doc/bn.tex b/doc/bn.tex
index 6f1cb8cd4..1dfb34d55 100644
--- a/doc/bn.tex
+++ b/doc/bn.tex
@@ -2409,9 +2409,25 @@ \subsection{From ASCII}
 mp_err mp_read_radix (mp_int *a, const char *str, int radix);
 \end{alltt}
 This will read a \texttt{NUL} terminated string in base \texttt{radix} from \texttt{str} into $a$.
-It will stop reading when it reads a character it does not recognize (which happens to include the
-\texttt{NUL} char\dots imagine that\dots).  A single leading $-$ (ASCII \texttt{0x20}) sign can be
-used to denote a negative number. The input encoding is currently restricted to ASCII only.
+Valid values of \texttt{radix} are in the range $[2, 64]$.
+%It will stop reading when it reads a character it does not recognize (which happens to include the
+%\texttt{NUL} char\dots imagine that\dots).
+
+It returns \texttt{MP\_VAL} for any character {\em not} in the range allowed for the given base.
+The list of characters is the same as for base-64 and also in the same order.
+\begin{alltt}
+0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz+/
+\end{alltt}
+
+A single leading $-$ (ASCII \texttt{0x20}) sign can be used to denote a negative number. The
+plus sign $+$ (ASCII \texttt{0x2b}) is already in use (bases 63 and 64) and cannot be used
+to denote positivity, no matter how good the mood of the number is.
+
+For all bases smaller than 37 the list is case-insensitive, e.g.:~the two hexadecimal numbers
+$123abc_{16} = 1194684_{10}$ and $123ABC_{16} = 1194684_{10}$ are equivalent but the two base
+64 numbers $123abc_{64} = 1108232550_{10}$ and $123ABC_{64} = 1108124364_{10}$ are not.
+
+The input encoding is currently restricted to ASCII only.
 
 If \texttt{MP\_NO\_FILE} is not defined a function to read from a file is also available.
 \index{mp\_fread}