Import Upstream version 0.8.2
[platform/upstream/mpc.git] / src / inp_str.c
1 /* mpc_inp_str -- Input a complex number from a given stream.
2
3 Copyright (C) 2009 Andreas Enge, Philippe Th\'eveny, Paul Zimmermann
4
5 This file is part of the MPC Library.
6
7 The MPC Library is free software; you can redistribute it and/or modify
8 it under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or (at your
10 option) any later version.
11
12 The MPC Library is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14 or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
15 License for more details.
16
17 You should have received a copy of the GNU Lesser General Public License
18 along with the MPC Library; see the file COPYING.LIB.  If not, write to
19 the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
20 MA 02111-1307, USA. */
21
22 #include <stdio.h> /* for FILE */
23 #include <ctype.h>
24 #include <string.h>
25 #include "mpc-impl.h"
26
27 static size_t
28 skip_whitespace (FILE *stream) {
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
111     /* (n-char-sequence) only after a NaN */
112     if ((nread != 3
113          || tolower ((unsigned char) (str[0])) != 'n'
114          || tolower ((unsigned char) (str[1])) != 'a'
115          || tolower ((unsigned char) (str[2])) != 'n')
116         && (nread != 5
117             || str[0] != '@'
118             || tolower ((unsigned char) (str[1])) != 'n'
119             || tolower ((unsigned char) (str[2])) != 'a'
120             || tolower ((unsigned char) (str[3])) != 'n'
121             || str[4] != '@')) {
122       ungetc (c, stream);
123       return str;
124     }
125
126     suffix = extract_suffix (stream);
127     nread += strlen (suffix) + 1;
128     if (nread >= strsize) {
129       str = mpc_realloc_str (str, strsize, nread + 1);
130       strsize = nread + 1;
131     }
132
133     /* Warning: the sprintf does not allow overlap between arguments. */
134     n = lenstr + sprintf (str + lenstr, "(%s", suffix);
135     MPC_ASSERT (n == nread);
136
137     c = getc (stream);
138     if (c == ')') {
139       str = mpc_realloc_str (str, strsize, nread + 2);
140       strsize = nread + 2;
141       str [nread] = c;
142       str [nread+1] = '\0';
143       nread++;
144     }
145     else if (c != EOF)
146       ungetc (c, stream);
147
148     mpc_free_str (suffix);
149   }
150   else if (c != EOF)
151     ungetc (c, stream);
152
153   return str;
154 }
155
156
157 int
158 mpc_inp_str (mpc_ptr rop, FILE *stream, size_t *read, int base,
159 mpc_rnd_t rnd_mode)
160 {
161    size_t white, nread = 0;
162    int inex = -1;
163    int c;
164    char *str;
165
166    if (stream == NULL)
167       stream = stdin;
168
169    white = skip_whitespace (stream);
170    c = getc (stream);
171    if (c != EOF) {
172      if (c == '(') {
173        char *real_str;
174        char *imag_str;
175        size_t n;
176
177        nread++; /* the opening parenthesis */
178        white = skip_whitespace (stream);
179        real_str = extract_string (stream);
180        nread += strlen(real_str);
181
182        c = getc (stream);
183        if (!isspace ((unsigned int) c)) {
184          if (c != EOF)
185            ungetc (c, stream);
186          mpc_free_str (real_str);
187          goto error;
188        }
189        else
190          ungetc (c, stream);
191
192        white += skip_whitespace (stream);
193        imag_str = extract_string (stream);
194        nread += strlen (imag_str);
195
196        str = mpc_alloc_str (nread + 2);
197        n = sprintf (str, "(%s %s", real_str, imag_str);
198        MPC_ASSERT (n == nread + 1);
199        mpc_free_str (real_str);
200        mpc_free_str (imag_str);
201
202        white += skip_whitespace (stream);
203        c = getc (stream);
204        if (c == ')') {
205          str = mpc_realloc_str (str, nread +2, nread + 3);
206          str [nread+1] = c;
207          str [nread+2] = '\0';
208          nread++;
209        }
210        else if (c != EOF)
211          ungetc (c, stream);
212      }
213      else {
214        if (c != EOF)
215          ungetc (c, stream);
216        str = extract_string (stream);
217        nread += strlen (str);
218      }
219
220      inex = mpc_set_str (rop, str, base, rnd_mode);
221
222      mpc_free_str (str);
223    }
224
225 error:
226    if (inex == -1) {
227       mpfr_set_nan (MPC_RE(rop));
228       mpfr_set_nan (MPC_IM(rop));
229    }
230    if (read != NULL)
231      *read = white + nread;
232    return inex;
233 }