1 /* Copyright (C) 1994, 1995, 1997, 1998, 1999 artofcode LLC. All rights reserved.
2
3 This program is free software; you can redistribute it and/or modify it
4 under the terms of the GNU General Public License as published by the
5 Free Software Foundation; either version 2 of the License, or (at your
6 option) any later version.
7
8 This program is distributed in the hope that it will be useful, but
9 WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 General Public License for more details.
12
13 You should have received a copy of the GNU General Public License along
14 with this program; if not, write to the Free Software Foundation, Inc.,
15 59 Temple Place, Suite 330, Boston, MA, 02111-1307.
16
17 */
18
19 /*$Id: iscannum.c,v 1.3.2.1.2.1 2003/01/17 00:49:04 giles Exp $ */
20 /* Number scanner for Ghostscript interpreter */
21 #include "math_.h"
22 #include "ghost.h"
23 #include "errors.h"
24 #include "scommon.h"
25 #include "iscannum.h" /* defines interface */
26 #include "scanchar.h"
27 #include "store.h"
28
29 /*
30 * Warning: this file has a "spaghetti" control structure. But since this
31 * code accounts for over 10% of the execution time of some PostScript
32 * files, this is one of the few places we feel this is justified.
33 */
34
35 /*
36 * Scan a number. If the number consumes the entire string, return 0;
37 * if not, set *psp to the first character beyond the number and return 1.
38 */
39 int
scan_number(const byte * str,const byte * end,int sign,ref * pref,const byte ** psp)40 scan_number(const byte * str, const byte * end, int sign,
41 ref * pref, const byte ** psp)
42 {
43 const byte *sp = str;
44 #define GET_NEXT(cvar, sp, end_action)\
45 if (sp >= end) { end_action; } else cvar = *sp++
46
47 /*
48 * Powers of 10 up to 6 can be represented accurately as
49 * a single-precision float.
50 */
51 #define NUM_POWERS_10 6
52 static const float powers_10[NUM_POWERS_10 + 1] = {
53 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6
54 };
55 static const double neg_powers_10[NUM_POWERS_10 + 1] = {
56 1e0, 1e-1, 1e-2, 1e-3, 1e-4, 1e-5, 1e-6
57 };
58
59 int ival;
60 double dval;
61 int exp10;
62 int code = 0;
63 int c, d;
64 const byte *const decoder = scan_char_decoder;
65 #define IS_DIGIT(d, c)\
66 ((d = decoder[c]) < 10)
67 #define WOULD_OVERFLOW(val, d, maxv)\
68 (val >= maxv / 10 && (val > maxv / 10 || d > (int)(maxv % 10)))
69
70 GET_NEXT(c, sp, return_error(e_syntaxerror));
71 if (!IS_DIGIT(d, c)) {
72 if (c != '.')
73 return_error(e_syntaxerror);
74 /* Might be a number starting with '.'. */
75 GET_NEXT(c, sp, return_error(e_syntaxerror));
76 if (!IS_DIGIT(d, c))
77 return_error(e_syntaxerror);
78 ival = 0;
79 goto i2r;
80 }
81 /* Accumulate an integer in ival. */
82 /* Do up to 4 digits without a loop, */
83 /* since we know this can't overflow and since */
84 /* most numbers have 4 (integer) digits or fewer. */
85 ival = d;
86 if (end - sp >= 3) { /* just check once */
87 if (!IS_DIGIT(d, (c = *sp))) {
88 sp++;
89 goto ind;
90 }
91 ival = ival * 10 + d;
92 if (!IS_DIGIT(d, (c = sp[1]))) {
93 sp += 2;
94 goto ind;
95 }
96 ival = ival * 10 + d;
97 sp += 3;
98 if (!IS_DIGIT(d, (c = sp[-1])))
99 goto ind;
100 ival = ival * 10 + d;
101 }
102 for (;; ival = ival * 10 + d) {
103 GET_NEXT(c, sp, goto iret);
104 if (!IS_DIGIT(d, c))
105 break;
106 if (WOULD_OVERFLOW((unsigned)ival, d, max_int)) {
107 /* goto i2l; */
108 if (ival == max_int / 10 && d == (max_int % 10) + 1 && sign < 0) {
109 GET_NEXT(c, sp, c= EOFC);
110 dval = -(double)min_int;
111 if (c == 'e' || c == 'E') {
112 exp10 = 0;
113 goto fs;
114 } else if (c == '.') {
115 GET_NEXT(c, sp, c = EOFC);
116 exp10 = 0;
117 goto fd;
118 } else if (!IS_DIGIT(d, c)) {
119 ival = min_int;
120 break;
121 }
122 } else
123 dval = ival;
124 goto l2d;
125 }
126 }
127 ind: /* We saw a non-digit while accumulating an integer in ival. */
128 switch (c) {
129 case '.':
130 GET_NEXT(c, sp, c = EOFC);
131 goto i2r;
132 default:
133 *psp = sp;
134 code = 1;
135 break;
136 case EOFC:
137 break;
138 case 'e':
139 case 'E':
140 if (sign < 0)
141 ival = -ival;
142 dval = ival;
143 exp10 = 0;
144 goto fe;
145 case '#':
146 {
147 const int radix = ival;
148 uint uval = 0, imax;
149
150 if (sign || radix < min_radix || radix > max_radix)
151 return_error(e_syntaxerror);
152 /* Avoid multiplies for power-of-2 radix. */
153 if (!(radix & (radix - 1))) {
154 int shift;
155
156 switch (radix) {
157 case 2:
158 shift = 1, imax = max_uint >> 1;
159 break;
160 case 4:
161 shift = 2, imax = max_uint >> 2;
162 break;
163 case 8:
164 shift = 3, imax = max_uint >> 3;
165 break;
166 case 16:
167 shift = 4, imax = max_uint >> 4;
168 break;
169 case 32:
170 shift = 5, imax = max_uint >> 5;
171 break;
172 default: /* can't happen */
173 return_error(e_rangecheck);
174 }
175 for (;; uval = (uval << shift) + d) {
176 GET_NEXT(c, sp, break);
177 d = decoder[c];
178 if (d >= radix) {
179 *psp = sp;
180 code = 1;
181 break;
182 }
183 if (uval > imax)
184 return_error(e_limitcheck);
185 }
186 } else {
187 int irem = max_uint % radix;
188
189 imax = max_uint / radix;
190 for (;; uval = uval * radix + d) {
191 GET_NEXT(c, sp, break);
192 d = decoder[c];
193 if (d >= radix) {
194 *psp = sp;
195 code = 1;
196 break;
197 }
198 if (uval >= imax &&
199 (uval > imax || d > irem)
200 )
201 return_error(e_limitcheck);
202 }
203 }
204 make_int(pref, uval);
205 return code;
206 }
207 }
208 iret:
209 make_int(pref, (sign < 0 ? -ival : ival));
210 return code;
211
212 /* Accumulate a double in dval. */
213 l2d:
214 exp10 = 0;
215 for (;;) {
216 dval = dval * 10 + d;
217 GET_NEXT(c, sp, c = EOFC);
218 if (!IS_DIGIT(d, c))
219 break;
220 }
221 switch (c) {
222 case '.':
223 GET_NEXT(c, sp, c = EOFC);
224 exp10 = 0;
225 goto fd;
226 default:
227 *psp = sp;
228 code = 1;
229 /* falls through */
230 case EOFC:
231 if (sign < 0)
232 dval = -dval;
233 goto rret;
234 case 'e':
235 case 'E':
236 exp10 = 0;
237 goto fs;
238 case '#':
239 return_error(e_syntaxerror);
240 }
241
242 /* We saw a '.' while accumulating an integer in ival. */
243 i2r:
244 exp10 = 0;
245 while (IS_DIGIT(d, c)) {
246 if (WOULD_OVERFLOW(ival, d, max_int)) {
247 dval = ival;
248 goto fd;
249 }
250 ival = ival * 10 + d;
251 exp10--;
252 GET_NEXT(c, sp, c = EOFC);
253 }
254 if (sign < 0)
255 ival = -ival;
256 /* Take a shortcut for the common case */
257 if (!(c == 'e' || c == 'E' || exp10 < -NUM_POWERS_10)) { /* Check for trailing garbage */
258 if (c != EOFC)
259 *psp = sp, code = 1;
260 make_real(pref, ival * neg_powers_10[-exp10]);
261 return code;
262 }
263 dval = ival;
264 goto fe;
265
266 /* Now we are accumulating a double in dval. */
267 fd:
268 while (IS_DIGIT(d, c)) {
269 dval = dval * 10 + d;
270 exp10--;
271 GET_NEXT(c, sp, c = EOFC);
272 }
273 fs:
274 if (sign < 0)
275 dval = -dval;
276 fe:
277 /* Now dval contains the value, negated if necessary. */
278 switch (c) {
279 case 'e':
280 case 'E':
281 { /* Check for a following exponent. */
282 int esign = 0;
283 int iexp;
284
285 GET_NEXT(c, sp, return_error(e_syntaxerror));
286 switch (c) {
287 case '-':
288 esign = 1;
289 case '+':
290 GET_NEXT(c, sp, return_error(e_syntaxerror));
291 }
292 /* Scan the exponent. We limit it arbitrarily to 999. */
293 if (!IS_DIGIT(d, c))
294 return_error(e_syntaxerror);
295 iexp = d;
296 for (;; iexp = iexp * 10 + d) {
297 GET_NEXT(c, sp, break);
298 if (!IS_DIGIT(d, c)) {
299 *psp = sp;
300 code = 1;
301 break;
302 }
303 if (iexp > 99)
304 return_error(e_limitcheck);
305 }
306 if (esign)
307 exp10 -= iexp;
308 else
309 exp10 += iexp;
310 break;
311 }
312 default:
313 *psp = sp;
314 code = 1;
315 case EOFC:
316 ;
317 }
318 /* Compute dval * 10^exp10. */
319 if (exp10 > 0) {
320 while (exp10 > NUM_POWERS_10)
321 dval *= powers_10[NUM_POWERS_10],
322 exp10 -= NUM_POWERS_10;
323 if (exp10 > 0)
324 dval *= powers_10[exp10];
325 } else if (exp10 < 0) {
326 while (exp10 < -NUM_POWERS_10)
327 dval /= powers_10[NUM_POWERS_10],
328 exp10 += NUM_POWERS_10;
329 if (exp10 < 0)
330 dval /= powers_10[-exp10];
331 }
332 /*
333 * Check for an out-of-range result. Currently we don't check for
334 * absurdly large numbers of digits in the accumulation loops,
335 * but we should.
336 */
337 if (dval >= 0) {
338 if (dval > MAX_FLOAT)
339 return_error(e_limitcheck);
340 } else {
341 if (dval < -MAX_FLOAT)
342 return_error(e_limitcheck);
343 }
344 rret:
345 make_real(pref, dval);
346 return code;
347 }
348