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
skip_whitespace(FILE * stream)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 *
extract_suffix(FILE * stream)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 *
extract_string(FILE * stream)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
mpc_inp_str(mpc_ptr rop,FILE * stream,size_t * read,int base,mpc_rnd_t rnd_mode)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