|
|
1.1 root 1: /*
2: * libc/stdio/_dscan.c
3: * ANSI-compliant C standard i/o library internals.
4: * _dscan(), _dassign()
5: * ANSI 4.9.6.2.
6: * Floating point support for _scanf().
7: * Kept in a separate source to allow scanf() et al. to link
8: * without floating point support.
9: */
10:
11: #include <stdio.h>
12: #include <stdlib.h>
13:
14: #if 0
15: #include <locale.h>
16: #else
17: #define _decimal_point '.'
18: #endif
19:
20: /* Compile-time options. */
21: #define LONGDOUBLE 0 /* iff sizeof(double) != sizeof(long double) */
22:
23: /*
24: * Read an ASCII floating point number
25: * containing at most 'width' characters from 'fp' into 'buf'.
26: * Convert the result using strtod() and store it through *dp.
27: * Return the number of characters read.
28: * Use the finite state machine shown below. In the diagram,
29: * states are in (parens)
30: * inputs are in [brackets]
31: * For all inputs not shown, transition is to (end) state.
32: * --
33: * / \
34: * v \
35: * ----------> [0-9] -> (3)
36: * / ^ | \
37: * / / | \
38: * / / v \
39: * / / [.] \ ->[+-] -
40: * / / | \ / \
41: * / / | \ / \
42: * / / v v / v
43: * (0) --> [+-] -> (1) (4) --> [Ee] -> (6) -> [0-9] -> (7)
44: * \ / / ^ ^ /
45: * \ / / / \ /
46: * \ / / / --
47: * \ / / /
48: * \ / / /
49: * \ / / /
50: * v v /
51: * [.] --> (2) -> [0-9] -> (5)
52: * ^ /
53: * \ /
54: * --
55: * This cannot be done correctly with the single character pushback
56: * guaranteed by ungetc(); for example, rejecting "+y", "1Ex" or "1E+x"
57: * requires two or three character pushback.
58: */
59: int
60: _dscan(buf, fp, width, dp) register char *buf; FILE *fp; int width; double *dp;
61: {
62: register int c, state, count;
63: register char *cp;
64:
65: cp = buf;
66: for (state = count = 0; count < width; ++count) {
67: *cp++ = c = getc(fp);
68: switch (c) {
69: case '+':
70: case '-':
71: if (state != 0 && state != 6)
72: break;
73: state++;
74: continue;
75: case '0':
76: case '1':
77: case '2':
78: case '3':
79: case '4':
80: case '5':
81: case '6':
82: case '7':
83: case '8':
84: case '9':
85: if (state == 0 || state == 1 || state == 3)
86: state = 3;
87: else if (state == 2 || state == 4 || state == 5)
88: state = 5;
89: else if (state == 6 || state == 7)
90: state = 7;
91: else
92: break;
93: continue;
94: case 'E':
95: case 'e':
96: if (state < 3 || 5 < state)
97: break;
98: state = 6;
99: continue;
100: default:
101: if (c != _decimal_point)
102: break;
103: if (state <= 1)
104: state = 2;
105: else if (state == 3)
106: state++;
107: else
108: break;
109: continue;
110: }
111: --cp;
112: ungetc(c, fp);
113: break;
114: }
115: *cp = '\0';
116: *dp = strtod(buf, (char **)NULL);
117: return ((int)(cp - buf));
118: }
119:
120: /*
121: * Assign *dp through *vp, width depending on flag.
122: */
123: void
124: _dassign(vp, dp, flag) Void *vp; double *dp; int flag;
125: {
126: #if LONGDOUBLE
127: if (flag == 'L')
128: *(long double *)vp = (long double)*dp;
129: else if (flag == 'l')
130: #else
131: if (flag == 'L' || flag == 'l')
132: #endif
133: *(double *)vp = *dp;
134: else
135: *(float *)vp = (float)*dp;
136: }
137:
138: /* end of libc/stdio/_dscan.c */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.