xref: /titanic_50/usr/src/lib/libbc/libc/stdio/common/scanf.c (revision dfb96a4f56fb431b915bc67e5d9d5c8d4f4f6679)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 /*      Copyright (c) 1984 AT&T */
28 /*        All Rights Reserved   */
29 
30 #pragma ident	"%Z%%M%	%I%	%E% SMI"
31 
32 /*LINTLIBRARY*/
33 #include <stdio.h>
34 #include <ctype.h>
35 #include <stdarg.h>
36 #include <errno.h>
37 #include <string.h>
38 #include <malloc.h>
39 
40 #define ON	1
41 #define OFF	0
42 
43 #define ARGMAX  64
44 static unsigned char newap[ARGMAX * sizeof(double)];
45 static unsigned char newform[256];
46 
47 extern int _doscan();
48 
49 static int	format_arg(unsigned char *, unsigned char *, unsigned char *);
50 
51 int
52 scanf(char *fmt, ...)
53 {
54 	va_list ap;
55 	char *nf;
56 	int ret_val;
57 
58 
59 	va_start(ap, fmt);
60 	if (strlen(fmt) >= sizeof(newform)) {
61 		nf = malloc(strlen(fmt)+1);
62 		if (format_arg((unsigned char *)strcpy(nf, fmt), ap, newap)
63 		    == ON) {
64 			va_end(ap);
65 			ret_val = _doscan(stdin, nf, newap);
66 			free(nf);
67 			return(ret_val);
68 		}
69 		free(nf);
70 	} else if (format_arg((unsigned char *)strcpy(newform, fmt), ap, newap)
71 	    == ON) {
72 		va_end(ap);
73 		return(_doscan(stdin, newform, newap));
74 	}
75 	ret_val = _doscan(stdin, fmt, ap);
76 	va_end(ap);
77 	return (ret_val);
78 }
79 
80 int
81 fscanf(FILE *iop, char *fmt, ...)
82 {
83 	va_list ap;
84 	char *nf;
85 	int ret_val;
86 
87 #ifdef POSIX
88         if ( !(iop->_flag & (_IOREAD|_IORW)) ) {
89                 iop->_flag |= _IOERR;
90                 errno = EBADF;
91                 return (EOF);
92         }
93 #endif	/* POSIX */
94 	va_start(ap, fmt);
95 	if (strlen(fmt) >= sizeof(newform)) {
96 		nf = malloc(strlen(fmt)+1);
97 		if (format_arg((unsigned char *)strcpy(nf, fmt), ap, newap)
98 		    == ON) {
99 			va_end(ap);
100 			ret_val = _doscan(stdin, nf, newap);
101 			free(nf);
102 			return(ret_val);
103 		}
104 		free(nf);
105 	} else if (format_arg((unsigned char *)strcpy(newform, fmt), ap, newap)
106 	    == ON) {
107 		va_end(ap);
108 		return(_doscan(iop, newform, newap));
109 	}
110 	ret_val = _doscan(iop, fmt, ap);
111 	va_end(ap);
112 	return (ret_val);
113 }
114 
115 int
116 sscanf(char *str, char *fmt, ...)
117 {
118 	va_list ap;
119 	FILE strbuf;
120 	char *nf;
121 	int ret_val;
122 
123 	va_start(ap, fmt);
124 	strbuf._flag = _IOREAD|_IOSTRG;
125 	strbuf._ptr = strbuf._base = (unsigned char*)str;
126 	strbuf._cnt = strlen(str);
127 	strbuf._bufsiz = strbuf._cnt;
128 	if (strlen(fmt) >= sizeof(newform)) {
129 		nf = malloc(strlen(fmt)+1);
130 		if (format_arg((unsigned char *)strcpy(nf, fmt), ap, newap)
131 		    == ON) {
132 			va_end(ap);
133 			ret_val = _doscan(stdin, nf, newap);
134 			free(nf);
135 			return(ret_val);
136 		}
137 		free(nf);
138 	} else if (format_arg((unsigned char *)strcpy(newform, fmt), ap, newap)
139 	    == ON) {
140 		va_end(ap);
141 		return(_doscan(&strbuf, newform, newap));
142 	}
143 	ret_val = _doscan(&strbuf, fmt, ap);
144 	va_end(ap);
145 	return (ret_val);
146 }
147 
148 /*
149  * This function reorganises the format string and argument list.
150  */
151 
152 
153 #ifndef NL_ARGMAX
154 #define NL_ARGMAX	9
155 #endif
156 
157 struct al {
158 	int a_num;		/* arg # specified at this position */
159 	unsigned char *a_start;	/* ptr to 'n' part of '%n$' in format str */
160 	unsigned char *a_end;	/* ptr to '$'+1 part of '%n$' in format str */
161 	int *a_val;		/* pointers to arguments */
162 };
163 
164 static int
165 format_arg(unsigned char *format, unsigned char *list, unsigned char *newlist)
166 {
167 	unsigned char *aptr, *bptr, *cptr;
168 	int i, fcode, nl_fmt, num, length, j;
169 	unsigned char *fmtsav;
170 	struct al args[ARGMAX + 1];
171 
172 #ifdef VTEST
173 	{
174 		int fd;
175 		fd = creat("/tmp/SCANF", 0666);
176 	}
177 #endif
178 	for (i = 0; i <= ARGMAX; args[i++].a_num = 0);
179 	nl_fmt = 0;
180 	i = j = 1;
181 	while (*format) {
182 		while ((fcode = *format++) != '\0' && fcode != '%') ;
183 		if (!fcode || i > ARGMAX)
184 			break;
185 	charswitch:
186 		switch (fcode = *format++) {
187 		case 'l':
188 		case 'h':
189 			goto charswitch;
190 		case '0': case '1': case '2':
191 		case '3': case '4': case '5':
192 		case '6': case '7': case '8':
193 		case '9':
194 			num = fcode - '0';
195 			fmtsav = format;
196 			while (isdigit(fcode = *format)) {
197 				num = num * 10 + fcode - '0';
198 				format++;
199 			}
200 			if (*format == '$') {
201 				nl_fmt++;
202 				args[i].a_start = fmtsav - 1;
203 				args[i].a_end = ++format;
204 				if (num > NL_ARGMAX)
205 					num = num;
206 				args[i].a_num = num;
207 			}
208 			goto charswitch;
209 	/* now have arg type only to parse */
210 		case 'd': case 'u': case 'o':
211 		case 'x': case 'e': case 'f':
212 		case 'g': case 'c': case '[':
213 		case 's':
214 			if (nl_fmt == 0)
215 				return(OFF);
216 			if (!args[i].a_num) {
217 				args[i].a_start = args[i].a_end = format - 1;
218 				args[i].a_num = j++;
219 			}
220 			i++;
221 			break;
222 		case '*':
223 		case '%':
224 			break;
225 		default:
226 			format--;
227 			break;
228 		}
229 	}
230 	length = i;
231 	if (nl_fmt == 0)
232 		return (OFF);
233 	for (i = 1; i < length && args[i].a_num == 0; i++);
234 
235 	/*
236 	 * Reformat the format string
237 	 */
238 	cptr = aptr = args[i].a_start;
239 	do {
240 		bptr = args[i++].a_end;
241 		for (; i < length && args[i].a_num == 0; i++);
242 		if (i == length)
243 			while (*cptr++);
244 		else
245 			cptr = args[i].a_start;
246 		for (; bptr != cptr; *aptr++ = *bptr++);
247 	} while (i < length);
248 
249 	/*
250 	 * Create arglist
251 	 * assuming that pointer to all variable type have
252 	 * same size.
253 	 */
254 	for (i = 1; i < length; i++)
255 		args[i].a_val = ((int **)(list += sizeof(int *)))[-1];
256 
257 	for (i = 1; i < length; i++) {
258 		int **ptr;
259 		ptr = (int **)newlist;
260 		*ptr = args[args[i].a_num].a_val;
261 		newlist += sizeof(int *);
262 	}
263 	return(ON);
264 }
265