diff options
Diffstat (limited to 'mpc/src/inp_str.c')
-rw-r--r-- | mpc/src/inp_str.c | 239 |
1 files changed, 239 insertions, 0 deletions
diff --git a/mpc/src/inp_str.c b/mpc/src/inp_str.c new file mode 100644 index 0000000000..695a3adff6 --- /dev/null +++ b/mpc/src/inp_str.c @@ -0,0 +1,239 @@ +/* mpc_inp_str -- Input a complex number from a given stream. + +Copyright (C) 2009, 2010, 2011 INRIA + +This file is part of GNU MPC. + +GNU MPC is free software; you can redistribute it and/or modify it under +the terms of the GNU Lesser General Public License as published by the +Free Software Foundation; either version 3 of the License, or (at your +option) any later version. + +GNU MPC is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for +more details. + +You should have received a copy of the GNU Lesser General Public License +along with this program. If not, see http://www.gnu.org/licenses/ . +*/ + +#include <stdio.h> /* for FILE */ +#include <ctype.h> +#include <string.h> +#include "mpc-impl.h" + +static size_t +skip_whitespace (FILE *stream) +{ + int c = getc (stream); + size_t size = 0; + while (c != EOF && isspace ((unsigned char) c)) { + c = getc (stream); + size++; + } + if (c != EOF) + ungetc (c, stream); + return size; +} + +/* Extract from stream the longest string made up of alphanumeric char and + '_' (i.e. n-char-sequence). + The user must free the returned string. */ +static char * +extract_suffix (FILE *stream) +{ + int c; + size_t nread = 0; + size_t strsize = 100; + char *str = mpc_alloc_str (strsize); + + c = getc (stream); + while (isalnum ((unsigned char) c) || c == '_') { + str [nread] = (char) c; + nread++; + if (nread == strsize) { + str = mpc_realloc_str (str, strsize, 2 * strsize); + strsize *= 2; + } + c = getc (stream); + } + + str = mpc_realloc_str (str, strsize, nread + 1); + strsize = nread + 1; + str [nread] = '\0'; + + if (c != EOF) + ungetc (c, stream); + return str; +} + + +/* Extract from the stream the longest string of characters which are neither + whitespace nor brackets (except for an optional bracketed n-char_sequence + directly following nan or @nan@ independently of case). + The user must free the returned string. */ +static char * +extract_string (FILE *stream) +{ + int c; + size_t nread = 0; + size_t strsize = 100; + char *str = mpc_alloc_str (strsize); + size_t lenstr; + + c = getc (stream); + while (c != EOF && c != '\n' + && !isspace ((unsigned char) c) + && c != '(' && c != ')') { + str [nread] = (char) c; + nread++; + if (nread == strsize) { + str = mpc_realloc_str (str, strsize, 2 * strsize); + strsize *= 2; + } + c = getc (stream); + } + + str = mpc_realloc_str (str, strsize, nread + 1); + strsize = nread + 1; + str [nread] = '\0'; + + if (nread == 0) + return str; + + lenstr = nread; + + if (c == '(') { + size_t n; + char *suffix; + int ret; + + /* (n-char-sequence) only after a NaN */ + if ((nread != 3 + || tolower ((unsigned char) (str[0])) != 'n' + || tolower ((unsigned char) (str[1])) != 'a' + || tolower ((unsigned char) (str[2])) != 'n') + && (nread != 5 + || str[0] != '@' + || tolower ((unsigned char) (str[1])) != 'n' + || tolower ((unsigned char) (str[2])) != 'a' + || tolower ((unsigned char) (str[3])) != 'n' + || str[4] != '@')) { + ungetc (c, stream); + return str; + } + + suffix = extract_suffix (stream); + nread += strlen (suffix) + 1; + if (nread >= strsize) { + str = mpc_realloc_str (str, strsize, nread + 1); + strsize = nread + 1; + } + + /* Warning: the sprintf does not allow overlap between arguments. */ + ret = sprintf (str + lenstr, "(%s", suffix); + MPC_ASSERT (ret >= 0); + n = lenstr + (size_t) ret; + MPC_ASSERT (n == nread); + + c = getc (stream); + if (c == ')') { + str = mpc_realloc_str (str, strsize, nread + 2); + strsize = nread + 2; + str [nread] = (char) c; + str [nread+1] = '\0'; + nread++; + } + else if (c != EOF) + ungetc (c, stream); + + mpc_free_str (suffix); + } + else if (c != EOF) + ungetc (c, stream); + + return str; +} + + +int +mpc_inp_str (mpc_ptr rop, FILE *stream, size_t *read, int base, +mpc_rnd_t rnd_mode) +{ + size_t white, nread = 0; + int inex = -1; + int c; + char *str; + + if (stream == NULL) + stream = stdin; + + white = skip_whitespace (stream); + c = getc (stream); + if (c != EOF) { + if (c == '(') { + char *real_str; + char *imag_str; + size_t n; + int ret; + + nread++; /* the opening parenthesis */ + white = skip_whitespace (stream); + real_str = extract_string (stream); + nread += strlen(real_str); + + c = getc (stream); + if (!isspace ((unsigned int) c)) { + if (c != EOF) + ungetc (c, stream); + mpc_free_str (real_str); + goto error; + } + else + ungetc (c, stream); + + white += skip_whitespace (stream); + imag_str = extract_string (stream); + nread += strlen (imag_str); + + str = mpc_alloc_str (nread + 2); + ret = sprintf (str, "(%s %s", real_str, imag_str); + MPC_ASSERT (ret >= 0); + n = (size_t) ret; + MPC_ASSERT (n == nread + 1); + mpc_free_str (real_str); + mpc_free_str (imag_str); + + white += skip_whitespace (stream); + c = getc (stream); + if (c == ')') { + str = mpc_realloc_str (str, nread +2, nread + 3); + str [nread+1] = (char) c; + str [nread+2] = '\0'; + nread++; + } + else if (c != EOF) + ungetc (c, stream); + } + else { + if (c != EOF) + ungetc (c, stream); + str = extract_string (stream); + nread += strlen (str); + } + + inex = mpc_set_str (rop, str, base, rnd_mode); + + mpc_free_str (str); + } + +error: + if (inex == -1) { + mpfr_set_nan (mpc_realref(rop)); + mpfr_set_nan (mpc_imagref(rop)); + } + if (read != NULL) + *read = white + nread; + return inex; +} |