xref: /titanic_41/usr/src/lib/libbc/libc/stdio/common/scanf.c (revision 8eea8e29cc4374d1ee24c25a07f45af132db3499)
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 (c) 1995, by Sun Microsystems, Inc.
24  * All rights reserved.
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 <varargs.h>
36 #include <errno.h>
37 
38 #define ON	1
39 #define OFF	0
40 
41 #define ARGMAX  64
42 static unsigned char newap[ARGMAX * sizeof(double)];
43 static unsigned char newform[256];
44 extern char *strcpy();
45 extern char *malloc();
46 
47 extern int _doscan();
48 static int format_arg();
49 
50 /*VARARGS1*/
51 int
52 scanf(fmt, va_alist)
53 char *fmt;
54 va_dcl
55 {
56 	va_list ap;
57 	char *nf;
58 	int ret_val;
59 
60 	va_start(ap);
61 	if (strlen(fmt) >= sizeof(newform)) {
62 		nf = malloc(strlen(fmt)+1);
63 		if (format_arg(strcpy(nf, fmt), ap, newap) == ON) {
64 			ret_val = _doscan(stdin, nf, newap);
65 			free(nf);
66 			return(ret_val);
67 		}
68 		free(nf);
69 	} else if (format_arg(strcpy(newform, fmt), ap, newap) == ON) {
70 		return(_doscan(stdin, newform, newap));
71 	}
72 	return(_doscan(stdin, fmt, ap));
73 }
74 
75 /*VARARGS2*/
76 int
77 fscanf(iop, fmt, va_alist)
78 FILE *iop;
79 char *fmt;
80 va_dcl
81 {
82 	va_list ap;
83 	char *nf;
84 	int ret_val;
85 
86 	va_start(ap);
87 #ifdef POSIX
88         if ( !(iop->_flag & (_IOREAD|_IORW)) ) {
89                 iop->_flag |= _IOERR;
90                 errno = EBADF;
91                 return (EOF);
92         }
93 #endif POSIX
94 	if (strlen(fmt) >= sizeof(newform)) {
95 		nf = malloc(strlen(fmt)+1);
96 		if (format_arg(strcpy(nf, fmt), ap, newap) == ON) {
97 			ret_val = _doscan(stdin, nf, newap);
98 			free(nf);
99 			return(ret_val);
100 		}
101 		free(nf);
102 	} else if (format_arg(strcpy(newform, fmt), ap, newap) == ON) {
103 		return(_doscan(iop, newform, newap));
104 	}
105 	return(_doscan(iop, fmt, ap));
106 }
107 
108 /*VARARGS2*/
109 int
110 sscanf(str, fmt, va_alist)
111 register char *str;
112 char *fmt;
113 va_dcl
114 {
115 	va_list ap;
116 	FILE strbuf;
117 	char *nf;
118 	int ret_val;
119 
120 	va_start(ap);
121 	strbuf._flag = _IOREAD|_IOSTRG;
122 	strbuf._ptr = strbuf._base = (unsigned char*)str;
123 	strbuf._cnt = strlen(str);
124 	strbuf._bufsiz = strbuf._cnt;
125 	if (strlen(fmt) >= sizeof(newform)) {
126 		nf = malloc(strlen(fmt)+1);
127 		if (format_arg(strcpy(nf, fmt), ap, newap) == ON) {
128 			ret_val = _doscan(stdin, nf, newap);
129 			free(nf);
130 			return(ret_val);
131 		}
132 		free(nf);
133 	} else if (format_arg(strcpy(newform, fmt), ap, newap) == ON) {
134 		return(_doscan(&strbuf, newform, newap));
135 	}
136 	return(_doscan(&strbuf, fmt, ap));
137 }
138 
139 /*
140  * This function reorganises the format string and argument list.
141  */
142 
143 
144 #ifndef NL_ARGMAX
145 #define NL_ARGMAX	9
146 #endif
147 
148 struct al {
149 	int a_num;		/* arg # specified at this position */
150 	unsigned char *a_start;	/* ptr to 'n' part of '%n$' in format str */
151 	unsigned char *a_end;	/* ptr to '$'+1 part of '%n$' in format str */
152 	int *a_val;		/* pointers to arguments */
153 };
154 
155 static int
156 format_arg(format, list, newlist)
157 unsigned char *format, *list, *newlist;
158 {
159 	unsigned char *aptr, *bptr, *cptr;
160 	register i, fcode, nl_fmt, num, length, j;
161 	unsigned char *fmtsav;
162 	struct al args[ARGMAX + 1];
163 
164 #ifdef VTEST
165 	{
166 		int fd;
167 		fd = creat("/tmp/SCANF", 0666);
168 	}
169 #endif
170 	for (i = 0; i <= ARGMAX; args[i++].a_num = 0);
171 	nl_fmt = 0;
172 	i = j = 1;
173 	while (*format) {
174 		while ((fcode = *format++) != '\0' && fcode != '%') ;
175 		if (!fcode || i > ARGMAX)
176 			break;
177 	charswitch:
178 		switch (fcode = *format++) {
179 		case 'l':
180 		case 'h':
181 			goto charswitch;
182 		case '0': case '1': case '2':
183 		case '3': case '4': case '5':
184 		case '6': case '7': case '8':
185 		case '9':
186 			num = fcode - '0';
187 			fmtsav = format;
188 			while (isdigit(fcode = *format)) {
189 				num = num * 10 + fcode - '0';
190 				format++;
191 			}
192 			if (*format == '$') {
193 				nl_fmt++;
194 				args[i].a_start = fmtsav - 1;
195 				args[i].a_end = ++format;
196 				if (num > NL_ARGMAX)
197 					num = num;
198 				args[i].a_num = num;
199 			}
200 			goto charswitch;
201 	/* now have arg type only to parse */
202 		case 'd': case 'u': case 'o':
203 		case 'x': case 'e': case 'f':
204 		case 'g': case 'c': case '[':
205 		case 's':
206 			if (nl_fmt == 0)
207 				return(OFF);
208 			if (!args[i].a_num) {
209 				args[i].a_start = args[i].a_end = format - 1;
210 				args[i].a_num = j++;
211 			}
212 			i++;
213 			break;
214 		case '*':
215 		case '%':
216 			break;
217 		default:
218 			format--;
219 			break;
220 		}
221 	}
222 	length = i;
223 	if (nl_fmt == 0)
224 		return (OFF);
225 	for (i = 1; i < length && args[i].a_num == 0; i++);
226 
227 	/*
228 	 * Reformat the format string
229 	 */
230 	cptr = aptr = args[i].a_start;
231 	do {
232 		bptr = args[i++].a_end;
233 		for (; i < length && args[i].a_num == 0; i++);
234 		if (i == length)
235 			while (*cptr++);
236 		else
237 			cptr = args[i].a_start;
238 		for (; bptr != cptr; *aptr++ = *bptr++);
239 	} while (i < length);
240 
241 	/*
242 	 * Create arglist
243 	 * assuming that pointer to all variable type have
244 	 * same size.
245 	 */
246 	for (i = 1; i < length; i++)
247 		args[i].a_val = ((int **)(list += sizeof(int *)))[-1];
248 
249 	for (i = 1; i < length; i++) {
250 		int **ptr;
251 		ptr = (int **)newlist;
252 		*ptr = args[args[i].a_num].a_val;
253 		newlist += sizeof(int *);
254 	}
255 	return(ON);
256 }
257