1 /*
2 * Copyright (c) 1995-2018, NVIDIA CORPORATION. All rights reserved.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 *
16 */
17
18 /** \file
19 * \brief Utility module for extracting numerical values from a string.
20 */
21
22 /*
23 * __fortio_getnum() - extracts integer or __BIGREAL_T scalar values from
24 * a string. If successful, 0 is returned; otherwise, an i/o
25 * error code is returned. Output arguments are used to pass
26 * back a flag indicating integer or __BIGREAL_T, the value of the
27 * constant, and the number of characters processed for the numeric.
28 */
29
30 #include "global.h"
31 #include "format.h"
32
33 /* define a few things for run-time tracing */
34 static int dbgflag;
35 #undef DBGBIT
36 #define DBGBIT(v) (LOCAL_DEBUG && (dbgflag & v))
37
38 static char buf[128];
39 static char *buf_p = buf;
40 static int buf_size = sizeof(buf);
41
42 /*
43 * __fortio_getnum() - extracts integer or __BIGREAL_T scalar values from
44 * a string. If successful, 0 is returned; otherwise, an i/o
45 * error code is returned. Output arguments are used to pass
46 * back a flag indicating integer or __BIGREAL_T, the value of the
47 * constant, and the number of characters processed for the numeric.
48 */
49 int
__fortio_getnum(char * currc,int * type,void * _val,int * len,bool dc_flag)50 __fortio_getnum(
51 char *currc, /* pointer to string to convert */
52 int *type, /* 0 ==> integer, 1 ==> __BIGREAL_T
53 * 2 ==> integer*8 (TM_I8-only).
54 * 3 ==> VMS degenerate REAL (e.g., 'd6', '-d6', 'e',...)
55 */
56 void *_val, /* value of token to return (overloaded).
57 * C90 hack - declare formal as void *; cast later
58 */
59 int *len, /* # of chars in number */
60 bool dc_flag)
61 {
62 char c;
63 char *cp;
64 char *fcptr;
65 int ret_err;
66 char *ep;
67 char *bp;
68 char decimal_char = '.';
69 int itmp;
70 union {
71 __BIGINT_T i;
72 __BIGREAL_T d;
73 DBLINT64 i8v;
74 } * val; /* value of token to return */
75
76 if (dc_flag == TRUE)
77 decimal_char = ',';
78 else
79 decimal_char = '.';
80 val = _val;
81 ret_err = 0;
82 c = *(cp = currc);
83 if (c == '-' || c == '+')
84 c = *++cp;
85 if (c == decimal_char) {
86 *cp = '.';
87 c = *++cp;
88 if (!ISDIGIT(c))
89 goto junk0;
90 goto state2;
91 }
92 if (!ISDIGIT(c))
93 goto junk0;
94
95 /*state1: digits */
96 do {
97 c = *++cp;
98 } while (ISDIGIT(c));
99 if (c == decimal_char) {
100 *cp = '.';
101 goto state2;
102 }
103 if (c == 'e' || c == 'E' || c == 'd' || c == 'D')
104 goto state3;
105 if (c == '+' || c == '-')
106 goto state6;
107 goto return_integer;
108 state2: /* . digit [digits] or digits . [ digits ] */
109 do {
110 c = *++cp;
111 } while (ISDIGIT(c));
112 if (c == 'e' || c == 'E' || c == 'd' || c == 'D')
113 goto state3;
114 if (c == '+' || c == '-')
115 goto state6;
116 goto return_real;
117
118 state3: /* digits [ . [ digits ] ] { e | d } */
119 if (c == 'd' || c == 'D')
120 *cp = 'e'; /* to ensure that strtod works */
121 c = *++cp;
122 if (ISDIGIT(c))
123 goto state5;
124 if (c == '+' || c == '-')
125 goto state4;
126 /*
127 * VMS extension: no digits, +, or - after e or d
128 */
129 *(cp - 1) = ' ';
130 goto return_real;
131
132 state4: /* digits [ . [ digits ] ] { e | d } { + | - } */
133 c = *++cp;
134 if (!ISDIGIT(c)) {
135 /*
136 * VMS extension: no digits after { e | d } { + | - }
137 */
138 *(cp - 1) = ' ';
139 *(cp - 2) = ' ';
140 goto return_real;
141 }
142
143 state5: /* digits [ . [ digits ] ] { e | d } [ + | - ] digits */
144 c = *++cp;
145 if (ISDIGIT(c))
146 goto state5;
147 goto return_real;
148
149 state6: /* digits [ . [ digits ] ] { + | - } */
150 /*
151 * VMS extension - form real value where digits after +/- comprise the
152 * exponent. cp points to +/-.
153 */
154 ep = cp;
155 do { /* scan past exponent */
156 c = *++cp;
157 } while (ISDIGIT(c));
158 if ((cp - currc) + 2 > buf_size) {
159 buf_size = (cp - currc) + 64;
160 if (buf_p != buf)
161 free(buf_p);
162 buf_p = (char *)malloc(buf_size);
163 }
164 itmp = ep - currc;
165 memcpy(buf_p, currc, itmp);
166 bp = buf_p + itmp;
167 itmp = cp - ep;
168 if (itmp > 1) {
169 *bp++ = 'e';
170 memcpy(bp, ep, itmp);
171 bp += itmp;
172 }
173 *bp = '\0';
174 fcptr = NULL;
175 val->d = __io_strtod(buf_p, &fcptr);
176 if (fcptr == buf_p) {
177 /* illegal real constant */
178 ret_err = FIO_EERR_DATA_CONVERSION;
179 goto ret;
180 }
181 *type = 1;
182 goto ret;
183
184 junk0:
185 /*
186 * VMS extension: don't have digits after { + | - | . | +. | -. }
187 * Could have exponent of the form +/- digits after one of the above.
188 */
189 if (c == '+' || c == '-') {
190 c = *++cp;
191 while (ISDIGIT(c))
192 c = *++cp;
193 } else if (c == 'e' || c == 'E' || c == 'd' || c == 'D') {
194 c = *++cp;
195 if (c == '+' || c == '-')
196 c = *++cp;
197 while (ISDIGIT(c))
198 c = *++cp;
199 }
200 *type = 3;
201 val->i = 0;
202 goto ret;
203
204 return_integer:
205 *type = 0;
206 fcptr = NULL;
207 ret_err = __fort_atoxi32(currc, &val->i, cp - currc, 10);
208 if (ret_err) {
209 ret_err = __fort_atoxi64(currc, val->i8v, cp - currc, 10);
210 *type = 2;
211 }
212 if (ret_err)
213 /* illegal integer constant */
214 ret_err = FIO_EERR_DATA_CONVERSION;
215 goto ret;
216
217 return_real:
218 *type = 1;
219 fcptr = NULL;
220 val->d = __io_strtod(currc, &fcptr);
221 if (fcptr == currc)
222 /* illegal real constant */
223 ret_err = FIO_EERR_DATA_CONVERSION;
224
225 ret:
226 *len = cp - currc;
227 if (DBGBIT(0x1)) {
228 __io_printf("fio_getnum: type=%d, len=%d, ret_err=%d\n", *type, *len,
229 ret_err);
230 __io_printf(" str:#%.*s#, val:", *len, currc);
231 if (*type) {
232 __fortio_printbigreal(val->d);
233 __io_printf("\n");
234 } else
235 __io_printf("%d\n", val->i);
236 }
237 c = *cp;
238 if ((c == '\n') || (c == '\0') || (c == ',') || (c == ' ') || (c == '/') ||
239 (c == ';') || (c == '\t') || (c == '\r') || (c == ')') || (c == '*')) {
240 return ret_err;
241 }
242 ret_err = FIO_EERR_DATA_CONVERSION;
243 return ret_err;
244 }
245