diff options
Diffstat (limited to 'usr/src/lib/libbc/libc/stdio/common/scanf.c')
-rw-r--r-- | usr/src/lib/libbc/libc/stdio/common/scanf.c | 256 |
1 files changed, 256 insertions, 0 deletions
diff --git a/usr/src/lib/libbc/libc/stdio/common/scanf.c b/usr/src/lib/libbc/libc/stdio/common/scanf.c new file mode 100644 index 0000000000..0a54f708d4 --- /dev/null +++ b/usr/src/lib/libbc/libc/stdio/common/scanf.c @@ -0,0 +1,256 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright (c) 1995, by Sun Microsystems, Inc. + * All rights reserved. + */ + +/* Copyright (c) 1984 AT&T */ +/* All Rights Reserved */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +/*LINTLIBRARY*/ +#include <stdio.h> +#include <ctype.h> +#include <varargs.h> +#include <errno.h> + +#define ON 1 +#define OFF 0 + +#define ARGMAX 64 +static unsigned char newap[ARGMAX * sizeof(double)]; +static unsigned char newform[256]; +extern char *strcpy(); +extern char *malloc(); + +extern int _doscan(); +static int format_arg(); + +/*VARARGS1*/ +int +scanf(fmt, va_alist) +char *fmt; +va_dcl +{ + va_list ap; + char *nf; + int ret_val; + + va_start(ap); + if (strlen(fmt) >= sizeof(newform)) { + nf = malloc(strlen(fmt)+1); + if (format_arg(strcpy(nf, fmt), ap, newap) == ON) { + ret_val = _doscan(stdin, nf, newap); + free(nf); + return(ret_val); + } + free(nf); + } else if (format_arg(strcpy(newform, fmt), ap, newap) == ON) { + return(_doscan(stdin, newform, newap)); + } + return(_doscan(stdin, fmt, ap)); +} + +/*VARARGS2*/ +int +fscanf(iop, fmt, va_alist) +FILE *iop; +char *fmt; +va_dcl +{ + va_list ap; + char *nf; + int ret_val; + + va_start(ap); +#ifdef POSIX + if ( !(iop->_flag & (_IOREAD|_IORW)) ) { + iop->_flag |= _IOERR; + errno = EBADF; + return (EOF); + } +#endif POSIX + if (strlen(fmt) >= sizeof(newform)) { + nf = malloc(strlen(fmt)+1); + if (format_arg(strcpy(nf, fmt), ap, newap) == ON) { + ret_val = _doscan(stdin, nf, newap); + free(nf); + return(ret_val); + } + free(nf); + } else if (format_arg(strcpy(newform, fmt), ap, newap) == ON) { + return(_doscan(iop, newform, newap)); + } + return(_doscan(iop, fmt, ap)); +} + +/*VARARGS2*/ +int +sscanf(str, fmt, va_alist) +register char *str; +char *fmt; +va_dcl +{ + va_list ap; + FILE strbuf; + char *nf; + int ret_val; + + va_start(ap); + strbuf._flag = _IOREAD|_IOSTRG; + strbuf._ptr = strbuf._base = (unsigned char*)str; + strbuf._cnt = strlen(str); + strbuf._bufsiz = strbuf._cnt; + if (strlen(fmt) >= sizeof(newform)) { + nf = malloc(strlen(fmt)+1); + if (format_arg(strcpy(nf, fmt), ap, newap) == ON) { + ret_val = _doscan(stdin, nf, newap); + free(nf); + return(ret_val); + } + free(nf); + } else if (format_arg(strcpy(newform, fmt), ap, newap) == ON) { + return(_doscan(&strbuf, newform, newap)); + } + return(_doscan(&strbuf, fmt, ap)); +} + +/* + * This function reorganises the format string and argument list. + */ + + +#ifndef NL_ARGMAX +#define NL_ARGMAX 9 +#endif + +struct al { + int a_num; /* arg # specified at this position */ + unsigned char *a_start; /* ptr to 'n' part of '%n$' in format str */ + unsigned char *a_end; /* ptr to '$'+1 part of '%n$' in format str */ + int *a_val; /* pointers to arguments */ +}; + +static int +format_arg(format, list, newlist) +unsigned char *format, *list, *newlist; +{ + unsigned char *aptr, *bptr, *cptr; + register i, fcode, nl_fmt, num, length, j; + unsigned char *fmtsav; + struct al args[ARGMAX + 1]; + +#ifdef VTEST + { + int fd; + fd = creat("/tmp/SCANF", 0666); + } +#endif + for (i = 0; i <= ARGMAX; args[i++].a_num = 0); + nl_fmt = 0; + i = j = 1; + while (*format) { + while ((fcode = *format++) != '\0' && fcode != '%') ; + if (!fcode || i > ARGMAX) + break; + charswitch: + switch (fcode = *format++) { + case 'l': + case 'h': + goto charswitch; + case '0': case '1': case '2': + case '3': case '4': case '5': + case '6': case '7': case '8': + case '9': + num = fcode - '0'; + fmtsav = format; + while (isdigit(fcode = *format)) { + num = num * 10 + fcode - '0'; + format++; + } + if (*format == '$') { + nl_fmt++; + args[i].a_start = fmtsav - 1; + args[i].a_end = ++format; + if (num > NL_ARGMAX) + num = num; + args[i].a_num = num; + } + goto charswitch; + /* now have arg type only to parse */ + case 'd': case 'u': case 'o': + case 'x': case 'e': case 'f': + case 'g': case 'c': case '[': + case 's': + if (nl_fmt == 0) + return(OFF); + if (!args[i].a_num) { + args[i].a_start = args[i].a_end = format - 1; + args[i].a_num = j++; + } + i++; + break; + case '*': + case '%': + break; + default: + format--; + break; + } + } + length = i; + if (nl_fmt == 0) + return (OFF); + for (i = 1; i < length && args[i].a_num == 0; i++); + + /* + * Reformat the format string + */ + cptr = aptr = args[i].a_start; + do { + bptr = args[i++].a_end; + for (; i < length && args[i].a_num == 0; i++); + if (i == length) + while (*cptr++); + else + cptr = args[i].a_start; + for (; bptr != cptr; *aptr++ = *bptr++); + } while (i < length); + + /* + * Create arglist + * assuming that pointer to all variable type have + * same size. + */ + for (i = 1; i < length; i++) + args[i].a_val = ((int **)(list += sizeof(int *)))[-1]; + + for (i = 1; i < length; i++) { + int **ptr; + ptr = (int **)newlist; + *ptr = args[args[i].a_num].a_val; + newlist += sizeof(int *); + } + return(ON); +} |