1 /* mpc_inp_str -- Input a complex number from a given stream. 2 3 Copyright (C) 2009, 2010, 2011 INRIA 4 5 This file is part of GNU MPC. 6 7 GNU MPC is free software; you can redistribute it and/or modify it under 8 the terms of the GNU Lesser General Public License as published by the 9 Free Software Foundation; either version 3 of the License, or (at your 10 option) any later version. 11 12 GNU MPC is distributed in the hope that it will be useful, but WITHOUT ANY 13 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 14 FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for 15 more details. 16 17 You should have received a copy of the GNU Lesser General Public License 18 along with this program. If not, see http://www.gnu.org/licenses/ . 19 */ 20 21 #include <stdio.h> /* for FILE */ 22 #include <ctype.h> 23 #include <string.h> 24 #include "mpc-impl.h" 25 26 static size_t 27 skip_whitespace (FILE *stream) 28 { 29 int c = getc (stream); 30 size_t size = 0; 31 while (c != EOF && isspace ((unsigned char) c)) { 32 c = getc (stream); 33 size++; 34 } 35 if (c != EOF) 36 ungetc (c, stream); 37 return size; 38 } 39 40 /* Extract from stream the longest string made up of alphanumeric char and 41 '_' (i.e. n-char-sequence). 42 The user must free the returned string. */ 43 static char * 44 extract_suffix (FILE *stream) 45 { 46 int c; 47 size_t nread = 0; 48 size_t strsize = 100; 49 char *str = mpc_alloc_str (strsize); 50 51 c = getc (stream); 52 while (isalnum ((unsigned char) c) || c == '_') { 53 str [nread] = (char) c; 54 nread++; 55 if (nread == strsize) { 56 str = mpc_realloc_str (str, strsize, 2 * strsize); 57 strsize *= 2; 58 } 59 c = getc (stream); 60 } 61 62 str = mpc_realloc_str (str, strsize, nread + 1); 63 strsize = nread + 1; 64 str [nread] = '\0'; 65 66 if (c != EOF) 67 ungetc (c, stream); 68 return str; 69 } 70 71 72 /* Extract from the stream the longest string of characters which are neither 73 whitespace nor brackets (except for an optional bracketed n-char_sequence 74 directly following nan or @nan@ independently of case). 75 The user must free the returned string. */ 76 static char * 77 extract_string (FILE *stream) 78 { 79 int c; 80 size_t nread = 0; 81 size_t strsize = 100; 82 char *str = mpc_alloc_str (strsize); 83 size_t lenstr; 84 85 c = getc (stream); 86 while (c != EOF && c != '\n' 87 && !isspace ((unsigned char) c) 88 && c != '(' && c != ')') { 89 str [nread] = (char) c; 90 nread++; 91 if (nread == strsize) { 92 str = mpc_realloc_str (str, strsize, 2 * strsize); 93 strsize *= 2; 94 } 95 c = getc (stream); 96 } 97 98 str = mpc_realloc_str (str, strsize, nread + 1); 99 strsize = nread + 1; 100 str [nread] = '\0'; 101 102 if (nread == 0) 103 return str; 104 105 lenstr = nread; 106 107 if (c == '(') { 108 size_t n; 109 char *suffix; 110 int ret; 111 112 /* (n-char-sequence) only after a NaN */ 113 if ((nread != 3 114 || tolower ((unsigned char) (str[0])) != 'n' 115 || tolower ((unsigned char) (str[1])) != 'a' 116 || tolower ((unsigned char) (str[2])) != 'n') 117 && (nread != 5 118 || str[0] != '@' 119 || tolower ((unsigned char) (str[1])) != 'n' 120 || tolower ((unsigned char) (str[2])) != 'a' 121 || tolower ((unsigned char) (str[3])) != 'n' 122 || str[4] != '@')) { 123 ungetc (c, stream); 124 return str; 125 } 126 127 suffix = extract_suffix (stream); 128 nread += strlen (suffix) + 1; 129 if (nread >= strsize) { 130 str = mpc_realloc_str (str, strsize, nread + 1); 131 strsize = nread + 1; 132 } 133 134 /* Warning: the sprintf does not allow overlap between arguments. */ 135 ret = sprintf (str + lenstr, "(%s", suffix); 136 MPC_ASSERT (ret >= 0); 137 n = lenstr + (size_t) ret; 138 MPC_ASSERT (n == nread); 139 140 c = getc (stream); 141 if (c == ')') { 142 str = mpc_realloc_str (str, strsize, nread + 2); 143 strsize = nread + 2; 144 str [nread] = (char) c; 145 str [nread+1] = '\0'; 146 nread++; 147 } 148 else if (c != EOF) 149 ungetc (c, stream); 150 151 mpc_free_str (suffix); 152 } 153 else if (c != EOF) 154 ungetc (c, stream); 155 156 return str; 157 } 158 159 160 int 161 mpc_inp_str (mpc_ptr rop, FILE *stream, size_t *read, int base, 162 mpc_rnd_t rnd_mode) 163 { 164 size_t white, nread = 0; 165 int inex = -1; 166 int c; 167 char *str; 168 169 if (stream == NULL) 170 stream = stdin; 171 172 white = skip_whitespace (stream); 173 c = getc (stream); 174 if (c != EOF) { 175 if (c == '(') { 176 char *real_str; 177 char *imag_str; 178 size_t n; 179 int ret; 180 181 nread++; /* the opening parenthesis */ 182 white = skip_whitespace (stream); 183 real_str = extract_string (stream); 184 nread += strlen(real_str); 185 186 c = getc (stream); 187 if (!isspace ((unsigned int) c)) { 188 if (c != EOF) 189 ungetc (c, stream); 190 mpc_free_str (real_str); 191 goto error; 192 } 193 else 194 ungetc (c, stream); 195 196 white += skip_whitespace (stream); 197 imag_str = extract_string (stream); 198 nread += strlen (imag_str); 199 200 str = mpc_alloc_str (nread + 2); 201 ret = sprintf (str, "(%s %s", real_str, imag_str); 202 MPC_ASSERT (ret >= 0); 203 n = (size_t) ret; 204 MPC_ASSERT (n == nread + 1); 205 mpc_free_str (real_str); 206 mpc_free_str (imag_str); 207 208 white += skip_whitespace (stream); 209 c = getc (stream); 210 if (c == ')') { 211 str = mpc_realloc_str (str, nread +2, nread + 3); 212 str [nread+1] = (char) c; 213 str [nread+2] = '\0'; 214 nread++; 215 } 216 else if (c != EOF) 217 ungetc (c, stream); 218 } 219 else { 220 if (c != EOF) 221 ungetc (c, stream); 222 str = extract_string (stream); 223 nread += strlen (str); 224 } 225 226 inex = mpc_set_str (rop, str, base, rnd_mode); 227 228 mpc_free_str (str); 229 } 230 231 error: 232 if (inex == -1) { 233 mpfr_set_nan (mpc_realref(rop)); 234 mpfr_set_nan (mpc_imagref(rop)); 235 } 236 if (read != NULL) 237 *read = white + nread; 238 return inex; 239 } 240