]> pd.if.org Git - pdclib/blob - functions/_PDCLIB/scan.c
Getting closer to scan().
[pdclib] / functions / _PDCLIB / scan.c
1 /* $Id$ */
2
3 /* _PDCLIB_scan( const char *, struct _PDCLIB_status_t * )
4
5    This file is part of the Public Domain C Library (PDCLib).
6    Permission is granted to use, modify, and / or redistribute at will.
7 */
8
9 #include <stdio.h>
10 #include <stdbool.h>
11 #include <stdlib.h>
12 #include <stdarg.h>
13
14 /* Using an integer's bits as flags for both the conversion flags and length
15    modifiers.
16 */
17 #define E_suppressed 1<<0
18 #define E_char       1<<6
19 #define E_short      1<<7
20 #define E_long       1<<8
21 #define E_llong      1<<9
22 #define E_intmax     1<<10
23 #define E_size       1<<11
24 #define E_ptrdiff    1<<12
25 #define E_intptr     1<<13
26 #define E_ldouble    1<<14
27 #define E_unsigned   1<<16
28
29
30 static bool MATCH( const char x, struct _PDCLIB_status_t * status )
31 {
32     if ( status->stream != NULL )
33     {
34         /* Matching against stream */
35         if ( status->stream->buffer[ status->stream->bufidx ] == x )
36         {
37             getc( status->stream );
38             ++(status->i);
39             return true;
40         }
41         else
42         {
43             return false;
44         }
45     }
46     else
47     {
48         /* Matching against string */
49         if ( *(status->s) == x )
50         {
51             ++(status->s);
52             ++(status->i);
53             return true;
54         }
55         else
56         {
57             return false;
58         }
59     }
60 }
61
62
63 const char * _PDCLIB_scan( const char * spec, struct _PDCLIB_status_t * status )
64 {
65     const char * orig_spec = spec;
66     if ( *(++spec) == '%' )
67     {
68         /* %% -> match single '%' */
69         MATCH( *spec, status );
70         return ++spec;
71     }
72     /* Initializing status structure */
73     status->flags = 0;
74     status->base = 0;
75     status->this = 0;
76     status->width = 0;
77     status->prec = 0;
78
79     /* '*' suppresses assigning parsed value to variable */
80     if ( *spec == '*' )
81     {
82         status->flags |= E_suppressed;
83         ++spec;
84     }
85
86     /* If a width is given, strtol() will return its value. If not given,
87        strtol() will return zero. In both cases, endptr will point to the
88        rest of the conversion specifier - just what we need.
89     */
90     status->width = (int)strtol( spec, (char**)&spec, 10 );
91
92     /* Optional length modifier
93        We step one character ahead in any case, and step back only if we find
94        there has been no length modifier (or step ahead another character if it
95        has been "hh" or "ll").
96     */
97     switch ( *(spec++) )
98     {
99         case 'h':
100             if ( *spec == 'h' )
101             {
102                 /* hh -> char */
103                 status->flags |= E_char;
104                 ++spec;
105             }
106             else
107             {
108                 /* h -> short */
109                 status->flags |= E_short;
110             }
111             break;
112         case 'l':
113             if ( *spec == 'l' )
114             {
115                 /* ll -> long long */
116                 status->flags |= E_llong;
117                 ++spec;
118             }
119             else
120             {
121                 /* l -> long */
122                 status->flags |= E_long;
123             }
124             break;
125         case 'j':
126             /* j -> intmax_t, which might or might not be long long */
127             status->flags |= E_intmax;
128             break;
129         case 'z':
130             /* z -> size_t, which might or might not be unsigned int */
131             status->flags |= E_size;
132             break;
133         case 't':
134             /* t -> ptrdiff_t, which might or might not be long */
135             status->flags |= E_ptrdiff;
136             break;
137         case 'L':
138             /* L -> long double */
139             status->flags |= E_ldouble;
140             break;
141         default:
142             --spec;
143             break;
144     }
145
146     /* Conversion specifier */
147     switch ( *spec )
148     {
149         case 'd':
150             status->base = 10;
151             break;
152         case 'i':
153             /* status->base = 0; */
154             break;
155         case 'o':
156             status->base = 8;
157             status->flags |= E_unsigned;
158             break;
159         case 'u':
160             status->base = 10;
161             status->flags |= E_unsigned;
162             break;
163         case 'x':
164             status->base = 16;
165             status->flags |= E_unsigned;
166             break;
167         case 'f':
168         case 'F':
169         case 'e':
170         case 'E':
171         case 'g':
172         case 'G':
173         case 'a':
174         case 'A':
175             break;
176         case 'c':
177             /* TODO */
178             break;
179         case 's':
180             /* TODO */
181             break;
182         case 'p':
183             /* TODO */
184             status->base = 16;
185             status->flags |= E_unsigned;
186             break;
187         case 'n':
188         {
189             int * val = va_arg( status->arg, int * );
190             *val = status->i;
191             return ++spec;
192         }
193         default:
194             /* No conversion specifier. Bad conversion. */
195             return orig_spec;
196     }
197     /* TODO: Actual conversions */
198     return NULL;
199 }
200
201 #ifdef TEST
202 #include <_PDCLIB_test.h>
203
204 int main( void )
205 {
206     TESTCASE( NO_TESTDRIVER );
207     return TEST_RESULTS;
208 }
209
210 #endif