Import mpc-1.0.1 to new vendor branch
[dragonfly.git] / contrib / mpc / src / inp_str.c
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 }