00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072 #include <cfg/crt.h>
00073
00074 #include "nut_io.h"
00075
00076 #include <ctype.h>
00077 #include <limits.h>
00078 #include <stdlib.h>
00079 #include <string.h>
00080
00085
00086 #define CF_LONG 0x01
00087 #define CF_SUPPRESS 0x02
00088 #define CF_SIGNOK 0x04
00089 #define CF_NDIGITS 0x08
00090 #define CF_PFXOK 0x10
00091 #define CF_NZDIGITS 0x20
00092 #define CF_DPTOK 0x10
00093 #define CF_EXPOK 0x20
00094
00095
00096
00097
00098 #define CT_CHAR 0
00099 #define CT_STRING 2
00100 #define CT_INT 3
00101 #define CT_FLOAT 4
00102
00116 int _getf(int _getb(int, void *, size_t), int fd, CONST char *fmt, va_list ap)
00117 {
00118
00119 u_char cf;
00120 u_char ch;
00121 size_t width;
00122 u_char flags;
00123 u_char ct;
00124 u_char base;
00125 u_char ccnt = 0;
00126 u_char acnt = 0;
00127 u_char hcnt;
00128 char buf[16];
00129 char *cp;
00130 u_char ch_ready = 0;
00131
00132
00133 for (;;) {
00134 cf = *fmt++;
00135 if (cf == 0)
00136 return acnt;
00137
00138
00139
00140
00141 if (isspace(cf)) {
00142 for (;;) {
00143 if (_getb(fd, &ch, 1) != 1)
00144 break;
00145 if (!isspace(ch)) {
00146 ch_ready = 1;
00147 break;
00148 }
00149 }
00150 continue;
00151 }
00152
00153
00154
00155
00156 if (cf != '%') {
00157 if (!ch_ready && _getb(fd, &ch, 1) != 1)
00158 return ccnt ? acnt : EOF;
00159 if (ch != cf)
00160 return acnt;
00161 ch_ready = 0;
00162 continue;
00163 }
00164
00165 cf = *fmt++;
00166
00167
00168
00169 if (cf == '%') {
00170 if (!ch_ready && _getb(fd, &ch, 1) != 1)
00171 return ccnt ? acnt : EOF;
00172 if (ch != cf)
00173 return acnt;
00174 ch_ready = 0;
00175 continue;
00176 }
00177
00178
00179
00180
00181 width = 0;
00182 flags = 0;
00183 hcnt = 0;
00184 for (;;) {
00185 if (cf == '*')
00186 flags |= CF_SUPPRESS;
00187 else if (cf == 'l')
00188 flags |= CF_LONG;
00189 else if (cf == 'h')
00190 hcnt++;
00191 else if (cf >= '0' && cf <= '9')
00192 width = width * 10 + cf - '0';
00193 else
00194 break;
00195
00196 cf = *fmt++;
00197 }
00198
00199
00200
00201
00202 base = 10;
00203 ct = CT_INT;
00204 switch (cf) {
00205 case '\0':
00206 return EOF;
00207 case 's':
00208 ct = CT_STRING;
00209 break;
00210 case 'c':
00211 ct = CT_CHAR;
00212 break;
00213 case 'i':
00214 base = 0;
00215 break;
00216 case 'u':
00217 base = 10;
00218 break;
00219 case 'o':
00220 base = 8;
00221 break;
00222 case 'x':
00223 case 'X':
00224 flags |= CF_PFXOK;
00225 base = 16;
00226 break;
00227 #ifdef STDIO_FLOATING_POINT
00228 case 'e':
00229 case 'f':
00230 case 'F':
00231 case 'g':
00232 case 'G':
00233 ct = CT_FLOAT;
00234 break;
00235 #endif
00236 }
00237
00238
00239
00240
00241 if (ct == CT_CHAR) {
00242 if (width == 0)
00243 width = 1;
00244 if (flags & CF_SUPPRESS) {
00245 while (width > sizeof(buf)) {
00246 if (!ch_ready && _getb(fd, buf, sizeof(buf)) <= 0)
00247 return ccnt ? acnt : EOF;
00248 width -= sizeof(buf);
00249 }
00250 if (width)
00251 if (!ch_ready && _getb(fd, &buf, width) <= 0)
00252 return ccnt ? acnt : EOF;
00253 } else {
00254 if (!ch_ready && _getb(fd, (void *) va_arg(ap, char *), width) <= 0)
00255 return ccnt ? acnt : EOF;
00256 acnt++;
00257 }
00258 ch_ready = 0;
00259 ccnt++;
00260 continue;
00261 }
00262
00263
00264
00265
00266 if (!ch_ready && _getb(fd, &ch, 1) != 1)
00267 return ccnt ? acnt : EOF;
00268 ch_ready = 0;
00269 while (isspace(ch)) {
00270 if (_getb(fd, &ch, 1) != 1)
00271 return ccnt ? acnt : EOF;
00272 }
00273
00274
00275
00276
00277 if (ct == CT_STRING) {
00278 if (width == 0)
00279 width = 0xFFFF;
00280 if (flags & CF_SUPPRESS) {
00281 while (!isspace(ch)) {
00282 if (--width == 0)
00283 break;
00284 if (_getb(fd, &ch, 1) != 1)
00285 break;
00286 }
00287 } else {
00288 cp = va_arg(ap, char *);
00289 while (!isspace(ch)) {
00290 *cp++ = ch;
00291 if (--width == 0)
00292 break;
00293 if (_getb(fd, &ch, 1) != 1)
00294 break;
00295 }
00296 *cp = 0;
00297 acnt++;
00298 }
00299 ccnt++;
00300 }
00301
00302
00303
00304
00305 else if (ct == CT_INT) {
00306 if (width == 0 || width > sizeof(buf) - 1)
00307 width = sizeof(buf) - 1;
00308
00309 flags |= CF_SIGNOK | CF_NDIGITS | CF_NZDIGITS;
00310
00311 for (cp = buf; width; width--) {
00312 if (ch == '0') {
00313 if (base == 0) {
00314 base = 8;
00315 flags |= CF_PFXOK;
00316 }
00317 if (flags & CF_NZDIGITS)
00318 flags &= ~(CF_SIGNOK | CF_NZDIGITS | CF_NDIGITS);
00319 else
00320 flags &= ~(CF_SIGNOK | CF_PFXOK | CF_NDIGITS);
00321 } else if (ch >= '1' && ch <= '7') {
00322 if (base == 0)
00323 base = 10;
00324 flags &= ~(CF_SIGNOK | CF_PFXOK | CF_NDIGITS);
00325 } else if (ch == '8' || ch == '9') {
00326 if (base == 0)
00327 base = 10;
00328 else if (base <= 8)
00329 break;
00330 flags &= ~(CF_SIGNOK | CF_PFXOK | CF_NDIGITS);
00331 } else if ((ch >= 'A' && ch <= 'F')
00332 || (ch >= 'a' && ch <= 'f')) {
00333 if (base <= 10)
00334 break;
00335 flags &= ~(CF_SIGNOK | CF_PFXOK | CF_NDIGITS);
00336 } else if (ch == '-' || ch == '+') {
00337 if ((flags & CF_SIGNOK) == 0)
00338 break;
00339 flags &= ~CF_SIGNOK;
00340 } else if (ch == 'x' || ch == 'X') {
00341 if ((flags & CF_PFXOK) == 0)
00342 break;
00343 base = 16;
00344 flags &= ~CF_PFXOK;
00345 } else {
00346 ch_ready = 1;
00347 break;
00348 }
00349 *cp++ = ch;
00350 if (width > 1) {
00351 if (_getb(fd, &ch, 1) != 1)
00352 break;
00353 }
00354 }
00355
00356 if (flags & CF_NDIGITS)
00357 return acnt;
00358
00359 if ((flags & CF_SUPPRESS) == 0) {
00360 u_long res;
00361
00362 *cp = 0;
00363 res = strtol(buf, 0, base);
00364 if (flags & CF_LONG)
00365 *va_arg(ap, long *) = res;
00366 else if (hcnt == 1)
00367 *va_arg(ap, short *) = res;
00368 else if (hcnt)
00369 *va_arg(ap, char *) = res;
00370 else
00371 *va_arg(ap, int *) = res;
00372 acnt++;
00373 }
00374 ccnt++;
00375 }
00376 #ifdef STDIO_FLOATING_POINT
00377 else if (ct == CT_FLOAT) {
00378 if (width == 0 || width > sizeof(buf) - 1)
00379 width = sizeof(buf) - 1;
00380 flags |= CF_SIGNOK | CF_NDIGITS | CF_DPTOK | CF_EXPOK;
00381 for (cp = buf; width; width--) {
00382 if (ch >= '0' && ch <= '9')
00383 flags &= ~(CF_SIGNOK | CF_NDIGITS);
00384 else if (ch == '+' || ch == '-') {
00385 if ((flags & CF_SIGNOK) == 0)
00386 break;
00387 flags &= ~CF_SIGNOK;
00388 } else if (ch == '.') {
00389 if ((flags & CF_DPTOK) == 0)
00390 break;
00391 flags &= ~(CF_SIGNOK | CF_DPTOK);
00392 } else if (ch == 'e' || ch == 'E') {
00393 if ((flags & (CF_NDIGITS | CF_EXPOK)) != CF_EXPOK)
00394 break;
00395 flags = (flags & ~(CF_EXPOK | CF_DPTOK)) | CF_SIGNOK | CF_NDIGITS;
00396 } else {
00397 ch_ready = 1;
00398 break;
00399 }
00400 *cp++ = ch;
00401 if (_getb(fd, &ch, 1) != 1)
00402 break;
00403 }
00404 if (flags & CF_NDIGITS) {
00405 if (flags & CF_EXPOK)
00406 return acnt;
00407 }
00408 if ((flags & CF_SUPPRESS) == 0) {
00409 double res;
00410
00411 *cp = 0;
00412 res = strtod(buf, 0);
00413 *va_arg(ap, double *) = res;
00414 acnt++;
00415 }
00416 ccnt++;
00417 }
00418 #endif
00419 }
00420 }
00421