source: bootcd/isolinux/syslinux-6.03/com32/lib/vsscanf.c

Last change on this file was e16e8f2, checked in by Edwin Eefting <edwin@datux.nl>, 3 years ago

bootstuff

  • Property mode set to 100644
File size: 7.5 KB
Line 
1/*
2 * vsscanf.c
3 *
4 * vsscanf(), from which the rest of the scanf()
5 * family is built
6 */
7
8#include <ctype.h>
9#include <stdarg.h>
10#include <stddef.h>
11#include <inttypes.h>
12#include <string.h>
13#include <limits.h>
14#include <stdio.h>
15#include <sys/bitops.h>
16
17#ifndef LONG_BIT
18#define LONG_BIT (CHAR_BIT*sizeof(long))
19#endif
20
21enum flags {
22    FL_SPLAT = 0x01,            /* Drop the value, do not assign */
23    FL_WIDTH = 0x02,            /* Field width specified */
24    FL_MINUS = 0x04,            /* Negative number */
25};
26
27enum ranks {
28    rank_char = -2,
29    rank_short = -1,
30    rank_int = 0,
31    rank_long = 1,
32    rank_longlong = 2,
33    rank_ptr = INT_MAX          /* Special value used for pointers */
34};
35
36#define MIN_RANK        rank_char
37#define MAX_RANK        rank_longlong
38
39#define INTMAX_RANK     rank_longlong
40#define SIZE_T_RANK     rank_long
41#define PTRDIFF_T_RANK  rank_long
42
43enum bail {
44    bail_none = 0,              /* No error condition */
45    bail_eof,                   /* Hit EOF */
46    bail_err                    /* Conversion mismatch */
47};
48
49int vsscanf(const char *buffer, const char *format, va_list ap)
50{
51    const char *p = format;
52    char ch;
53    const char *q = buffer;
54    const char *qq;
55    uintmax_t val = 0;
56    int rank = rank_int;        /* Default rank */
57    unsigned int width = UINT_MAX;
58    int base;
59    enum flags flags = 0;
60    enum {
61        st_normal,              /* Ground state */
62        st_flags,               /* Special flags */
63        st_width,               /* Field width */
64        st_modifiers,           /* Length or conversion modifiers */
65        st_match_init,          /* Initial state of %[ sequence */
66        st_match,               /* Main state of %[ sequence */
67        st_match_range,         /* After - in a %[ sequence */
68    } state = st_normal;
69    char *sarg = NULL;          /* %s %c or %[ string argument */
70    enum bail bail = bail_none;
71    int converted = 0;          /* Successful conversions */
72    unsigned long matchmap[((1 << CHAR_BIT) + (LONG_BIT - 1)) / LONG_BIT];
73    int matchinv = 0;           /* Is match map inverted? */
74    unsigned char range_start = 0;
75
76    while ((ch = *p++) && !bail) {
77        switch (state) {
78        case st_normal:
79            if (ch == '%') {
80                state = st_flags;
81                flags = 0;
82                rank = rank_int;
83                width = UINT_MAX;
84            } else if (isspace((unsigned char)ch)) {
85                q = skipspace(q);
86            } else {
87                if (*q == ch)
88                    q++;
89                else
90                    bail = bail_err;    /* Match failure */
91            }
92            break;
93
94        case st_flags:
95            switch (ch) {
96            case '*':
97                flags |= FL_SPLAT;
98                break;
99            case '0' ... '9':
100                width = (ch - '0');
101                state = st_width;
102                flags |= FL_WIDTH;
103                break;
104            default:
105                state = st_modifiers;
106                p--;            /* Process this character again */
107                break;
108            }
109            break;
110
111        case st_width:
112            if (ch >= '0' && ch <= '9') {
113                width = width * 10 + (ch - '0');
114            } else {
115                state = st_modifiers;
116                p--;            /* Process this character again */
117            }
118            break;
119
120        case st_modifiers:
121            switch (ch) {
122                /* Length modifiers - nonterminal sequences */
123            case 'h':
124                rank--;         /* Shorter rank */
125                break;
126            case 'l':
127                rank++;         /* Longer rank */
128                break;
129            case 'j':
130                rank = INTMAX_RANK;
131                break;
132            case 'z':
133                rank = SIZE_T_RANK;
134                break;
135            case 't':
136                rank = PTRDIFF_T_RANK;
137                break;
138            case 'L':
139            case 'q':
140                rank = rank_longlong;   /* long double/long long */
141                break;
142
143            default:
144                /* Output modifiers - terminal sequences */
145                state = st_normal;      /* Next state will be normal */
146                if (rank < MIN_RANK)    /* Canonicalize rank */
147                    rank = MIN_RANK;
148                else if (rank > MAX_RANK)
149                    rank = MAX_RANK;
150
151                switch (ch) {
152                case 'P':       /* Upper case pointer */
153                case 'p':       /* Pointer */
154#if 0                           /* Enable this to allow null pointers by name */
155                    q = skipspace(q);
156                    if (!isdigit((unsigned char)*q)) {
157                        static const char *const nullnames[] =
158                            { "null", "nul", "nil", "(null)", "(nul)", "(nil)",
1590 };
160                        const char *const *np;
161
162                        /* Check to see if it's a null pointer by name */
163                        for (np = nullnames; *np; np++) {
164                            if (!strncasecmp(q, *np, strlen(*np))) {
165                                val = (uintmax_t) ((void *)NULL);
166                                goto set_integer;
167                            }
168                        }
169                        /* Failure */
170                        bail = bail_err;
171                        break;
172                    }
173                    /* else */
174#endif
175                    rank = rank_ptr;
176                    base = 0;
177                    goto scan_int;
178
179                case 'i':       /* Base-independent integer */
180                    base = 0;
181                    goto scan_int;
182
183                case 'd':       /* Decimal integer */
184                    base = 10;
185                    goto scan_int;
186
187                case 'o':       /* Octal integer */
188                    base = 8;
189                    goto scan_int;
190
191                case 'u':       /* Unsigned decimal integer */
192                    base = 10;
193                    goto scan_int;
194
195                case 'x':       /* Hexadecimal integer */
196                case 'X':
197                    base = 16;
198                    goto scan_int;
199
200                case 'n':       /* Number of characters consumed */
201                    val = (q - buffer);
202                    goto set_integer;
203
204scan_int:
205                    q = skipspace(q);
206                    if (!*q) {
207                        bail = bail_eof;
208                        break;
209                    }
210                    val = strntoumax(q, (char **)&qq, base, width);
211                    if (qq == q) {
212                        bail = bail_err;
213                        break;
214                    }
215                    q = qq;
216                    converted++;
217                    /* fall through */
218
219set_integer:
220                    if (!(flags & FL_SPLAT)) {
221                        switch (rank) {
222                        case rank_char:
223                            *va_arg(ap, unsigned char *) = (unsigned char)val;
224                            break;
225                        case rank_short:
226                            *va_arg(ap, unsigned short *) = (unsigned short)val;
227                            break;
228                        case rank_int:
229                            *va_arg(ap, unsigned int *) = (unsigned int)val;
230                            break;
231                        case rank_long:
232                            *va_arg(ap, unsigned long *) = (unsigned long)val;
233                            break;
234                        case rank_longlong:
235                            *va_arg(ap, unsigned long long *) =
236                                (unsigned long long)val;
237                            break;
238                        case rank_ptr:
239                            *va_arg(ap, void **) = (void *)(uintptr_t) val;
240                            break;
241                        }
242                    }
243                    break;
244
245                case 'c':       /* Character */
246                    width = (flags & FL_WIDTH) ? width : 1;     /* Default width == 1 */
247                    sarg = va_arg(ap, char *);
248                    while (width--) {
249                        if (!*q) {
250                            bail = bail_eof;
251                            break;
252                        }
253                        *sarg++ = *q++;
254                    }
255                    if (!bail)
256                        converted++;
257                    break;
258
259                case 's':       /* String */
260                    {
261                        char *sp;
262                        sp = sarg = va_arg(ap, char *);
263                        while (width-- && *q && !isspace((unsigned char)*q)) {
264                            *sp++ = *q++;
265                        }
266                        if (sarg != sp) {
267                            *sp = '\0'; /* Terminate output */
268                            converted++;
269                        } else {
270                            bail = bail_eof;
271                        }
272                    }
273                    break;
274
275                case '[':       /* Character range */
276                    sarg = va_arg(ap, char *);
277                    state = st_match_init;
278                    matchinv = 0;
279                    memset(matchmap, 0, sizeof matchmap);
280                    break;
281
282                case '%':       /* %% sequence */
283                    if (*q == '%')
284                        q++;
285                    else
286                        bail = bail_err;
287                    break;
288
289                default:        /* Anything else */
290                    bail = bail_err;    /* Unknown sequence */
291                    break;
292                }
293            }
294            break;
295
296        case st_match_init:     /* Initial state for %[ match */
297            if (ch == '^' && !matchinv) {
298                matchinv = 1;
299            } else {
300                range_start = (unsigned char)ch;
301                set_bit((unsigned char)ch, matchmap);
302                state = st_match;
303            }
304            break;
305
306        case st_match:          /* Main state for %[ match */
307            if (ch == ']') {
308                goto match_run;
309            } else if (ch == '-') {
310                state = st_match_range;
311            } else {
312                range_start = (unsigned char)ch;
313                set_bit((unsigned char)ch, matchmap);
314            }
315            break;
316
317        case st_match_range:    /* %[ match after - */
318            if (ch == ']') {
319                set_bit((unsigned char)'-', matchmap);  /* - was last character */
320                goto match_run;
321            } else {
322                int i;
323                for (i = range_start; i <= (unsigned char)ch; i++)
324                    set_bit(i, matchmap);
325                state = st_match;
326            }
327            break;
328
329match_run:                      /* Match expression finished */
330            qq = q;
331            while (width && *q
332                   && test_bit((unsigned char)*q, matchmap) ^ matchinv) {
333                *sarg++ = *q++;
334            }
335            if (q != qq) {
336                *sarg = '\0';
337                converted++;
338            } else {
339                bail = *q ? bail_err : bail_eof;
340            }
341            break;
342        }
343    }
344
345    if (bail == bail_eof && !converted)
346        converted = -1;         /* Return EOF (-1) */
347
348    return converted;
349}
Note: See TracBrowser for help on using the repository browser.