| /****************************************************************************** |
| * Copyright (c) 2004, 2008 IBM Corporation |
| * All rights reserved. |
| * This program and the accompanying materials |
| * are made available under the terms of the BSD License |
| * which accompanies this distribution, and is available at |
| * http://www.opensource.org/licenses/bsd-license.php |
| * |
| * Contributors: |
| * IBM Corporation - initial implementation |
| *****************************************************************************/ |
| |
| #include "string.h" |
| #include "ctype.h" |
| #include "stdlib.h" |
| #include "stdio.h" |
| #include "unistd.h" |
| |
| |
| static int |
| _getc(FILE * stream) |
| { |
| int count; |
| char c; |
| |
| if (stream->mode == _IONBF || stream->buf == NULL) { |
| if (read(stream->fd, &c, 1) == 1) |
| return (int) c; |
| else |
| return EOF; |
| } |
| |
| if (stream->pos == 0 || stream->pos >= BUFSIZ || |
| stream->buf[stream->pos] == '\0') { |
| count = read(stream->fd, stream->buf, BUFSIZ); |
| if (count < 0) |
| count = 0; |
| if (count < BUFSIZ) |
| stream->buf[count] = '\0'; |
| stream->pos = 0; |
| } |
| |
| return stream->buf[stream->pos++]; |
| } |
| |
| static void |
| _ungetc(int ch, FILE * stream) |
| { |
| if (stream->mode != _IONBF && stream->pos > 0) |
| stream->pos--; |
| } |
| |
| static int |
| _is_voidage(int ch) |
| { |
| if (ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r' || ch == '\0') |
| return 1; |
| else |
| return 0; |
| } |
| |
| |
| static int |
| _scanf(FILE * stream, const char *fmt, va_list * ap) |
| { |
| int i = 0; |
| int length = 0; |
| |
| fmt++; |
| |
| while (*fmt != '\0') { |
| |
| char tbuf[256]; |
| char ch; |
| |
| switch (*fmt) { |
| case 'd': |
| case 'i': |
| ch = _getc(stream); |
| if (length == 0) { |
| while (!_is_voidage(ch) && isdigit(ch)) { |
| tbuf[i] = ch; |
| ch = _getc(stream); |
| i++; |
| } |
| } else { |
| while (!_is_voidage(ch) && i < length |
| && isdigit(ch)) { |
| tbuf[i] = ch; |
| ch = _getc(stream); |
| i++; |
| } |
| } |
| /* We tried to understand what this is good for... |
| * but we did not. We know for sure that it does not |
| * work on SLOF if this is active. */ |
| /* _ungetc(ch, stream); */ |
| tbuf[i] = '\0'; |
| |
| /* ch = _getc(stream); */ |
| if (!_is_voidage(ch)) |
| _ungetc(ch, stream); |
| |
| if (strlen(tbuf) == 0) |
| return 0; |
| |
| *(va_arg(*ap, int *)) = strtol(tbuf, NULL, 10); |
| break; |
| case 'X': |
| case 'x': |
| ch = _getc(stream); |
| if (length == 0) { |
| while (!_is_voidage(ch) && isxdigit(ch)) { |
| tbuf[i] = ch; |
| ch = _getc(stream); |
| i++; |
| } |
| } else { |
| while (!_is_voidage(ch) && i < length |
| && isxdigit(ch)) { |
| tbuf[i] = ch; |
| ch = _getc(stream); |
| i++; |
| } |
| } |
| /* _ungetc(ch, stream); */ |
| tbuf[i] = '\0'; |
| |
| /* ch = _getc(stream); */ |
| if (!_is_voidage(ch)) |
| _ungetc(ch, stream); |
| |
| if (strlen(tbuf) == 0) |
| return 0; |
| |
| *(va_arg(*ap, int *)) = strtol(tbuf, NULL, 16); |
| break; |
| case 'O': |
| case 'o': |
| ch = _getc(stream); |
| if (length == 0) { |
| while (!_is_voidage(ch) |
| && !(ch < '0' || ch > '7')) { |
| tbuf[i] = ch; |
| ch = _getc(stream); |
| i++; |
| } |
| } else { |
| while (!_is_voidage(ch) && i < length |
| && !(ch < '0' || ch > '7')) { |
| tbuf[i] = ch; |
| ch = _getc(stream); |
| i++; |
| } |
| } |
| /* _ungetc(ch, stream); */ |
| tbuf[i] = '\0'; |
| |
| /* ch = _getc(stream); */ |
| if (!_is_voidage(ch)) |
| _ungetc(ch, stream); |
| |
| if (strlen(tbuf) == 0) |
| return 0; |
| |
| *(va_arg(*ap, int *)) = strtol(tbuf, NULL, 8); |
| break; |
| case 'c': |
| ch = _getc(stream); |
| while (_is_voidage(ch)) |
| ch = _getc(stream); |
| |
| *(va_arg(*ap, char *)) = ch; |
| |
| ch = _getc(stream); |
| if (!_is_voidage(ch)) |
| _ungetc(ch, stream); |
| |
| break; |
| case 's': |
| ch = _getc(stream); |
| if (length == 0) { |
| while (!_is_voidage(ch)) { |
| tbuf[i] = ch; |
| ch = _getc(stream); |
| i++; |
| } |
| } else { |
| while (!_is_voidage(ch) && i < length) { |
| tbuf[i] = ch; |
| ch = _getc(stream); |
| i++; |
| } |
| } |
| /* _ungetc(ch, stream); */ |
| tbuf[i] = '\0'; |
| |
| /* ch = _getc(stream); */ |
| if (!_is_voidage(ch)) |
| _ungetc(ch, stream); |
| |
| strcpy(va_arg(*ap, char *), tbuf); |
| break; |
| default: |
| if (*fmt >= '0' && *fmt <= '9') |
| length += *fmt - '0'; |
| break; |
| } |
| fmt++; |
| } |
| |
| return 1; |
| } |
| |
| |
| |
| int |
| vfscanf(FILE * stream, const char *fmt, va_list ap) |
| { |
| int args = 0; |
| |
| while (*fmt != '\0') { |
| |
| if (*fmt == '%') { |
| |
| char formstr[20]; |
| int i = 0; |
| |
| do { |
| formstr[i] = *fmt; |
| fmt++; |
| i++; |
| } while (! |
| (*fmt == 'd' || *fmt == 'i' || *fmt == 'x' |
| || *fmt == 'X' || *fmt == 'p' || *fmt == 'c' |
| || *fmt == 's' || *fmt == '%' || *fmt == 'O' |
| || *fmt == 'o')); |
| formstr[i++] = *fmt; |
| formstr[i] = '\0'; |
| if (*fmt != '%') { |
| if (_scanf(stream, formstr, &ap) <= 0) |
| return args; |
| else |
| args++; |
| } |
| |
| } |
| |
| fmt++; |
| |
| } |
| |
| return args; |
| } |
| |
| int |
| getc(FILE * stream) |
| { |
| return _getc(stream); |
| } |
| |
| int |
| getchar(void) |
| { |
| return _getc(stdin); |
| } |