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