scanf.c revision 722:636b850d4ee9
1179189Sjb/*
2179189Sjb * CDDL HEADER START
3321270Sngie *
4321270Sngie * The contents of this file are subject to the terms of the
5179189Sjb * Common Development and Distribution License, Version 1.0 only
6179189Sjb * (the "License").  You may not use this file except in compliance
7179189Sjb * with the License.
8179189Sjb *
9179189Sjb * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10179189Sjb * or http://www.opensolaris.org/os/licensing.
11179189Sjb * See the License for the specific language governing permissions
12179189Sjb * and limitations under the License.
13179189Sjb *
14179189Sjb * When distributing Covered Code, include this CDDL HEADER in each
15179189Sjb * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16179189Sjb * If applicable, add the following below this CDDL HEADER, with the
17179189Sjb * fields enclosed by brackets "[]" replaced with your own identifying
18179189Sjb * information: Portions Copyright [yyyy] [name of copyright owner]
19179189Sjb *
20179189Sjb * CDDL HEADER END
21211554Srpaulo */
22179189Sjb/*
23179189Sjb * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24179189Sjb * Use is subject to license terms.
25179189Sjb */
26179189Sjb
27179189Sjb/*      Copyright (c) 1984 AT&T */
28179189Sjb/*        All Rights Reserved   */
29179189Sjb
30179189Sjb#pragma ident	"%Z%%M%	%I%	%E% SMI"
31179189Sjb
32179189Sjb/*LINTLIBRARY*/
33179189Sjb#include <stdio.h>
34250574Smarkj#include <ctype.h>
35179189Sjb#include <stdarg.h>
36248708Spfg#include <errno.h>
37179189Sjb#include <string.h>
38179189Sjb#include <malloc.h>
39179189Sjb
40179189Sjb#define ON	1
41179189Sjb#define OFF	0
42179189Sjb
43179189Sjb#define ARGMAX  64
44179189Sjbstatic unsigned char newap[ARGMAX * sizeof(double)];
45179189Sjbstatic unsigned char newform[256];
46179189Sjb
47233415Sgonzoextern int _doscan();
48179189Sjb
49179189Sjbstatic int	format_arg(unsigned char *, unsigned char *, unsigned char *);
50238366Sgnn
51254889Smarkjint
52179189Sjbscanf(char *fmt, ...)
53179189Sjb{
54254889Smarkj	va_list ap;
55254889Smarkj	char *nf;
56179189Sjb	int ret_val;
57179189Sjb
58204597Suqs
59179189Sjb	va_start(ap, fmt);
60211554Srpaulo	if (strlen(fmt) >= sizeof(newform)) {
61321270Sngie		nf = malloc(strlen(fmt)+1);
62321270Sngie		if (format_arg((unsigned char *)strcpy(nf, fmt), ap, newap)
63321270Sngie		    == ON) {
64179189Sjb			va_end(ap);
65179189Sjb			ret_val = _doscan(stdin, nf, newap);
66179189Sjb			free(nf);
67179189Sjb			return(ret_val);
68179189Sjb		}
69179189Sjb		free(nf);
70179189Sjb	} else if (format_arg((unsigned char *)strcpy(newform, fmt), ap, newap)
71211725Simp	    == ON) {
72321270Sngie		va_end(ap);
73211554Srpaulo		return(_doscan(stdin, newform, newap));
74321270Sngie	}
75321270Sngie	ret_val = _doscan(stdin, fmt, ap);
76321270Sngie	va_end(ap);
77211725Simp	return (ret_val);
78179189Sjb}
79321270Sngie
80233415Sgonzoint
81233415Sgonzofscanf(FILE *iop, char *fmt, ...)
82321270Sngie{
83321270Sngie	va_list ap;
84242723Sjhibbits	char *nf;
85242723Sjhibbits	int ret_val;
86321270Sngie
87321270Sngie#ifdef POSIX
88179189Sjb        if ( !(iop->_flag & (_IOREAD|_IORW)) ) {
89179189Sjb                iop->_flag |= _IOERR;
90179189Sjb                errno = EBADF;
91179189Sjb                return (EOF);
92179189Sjb        }
93211554Srpaulo#endif	/* POSIX */
94233415Sgonzo	va_start(ap, fmt);
95211554Srpaulo	if (strlen(fmt) >= sizeof(newform)) {
96211554Srpaulo		nf = malloc(strlen(fmt)+1);
97211554Srpaulo		if (format_arg((unsigned char *)strcpy(nf, fmt), ap, newap)
98179189Sjb		    == ON) {
99179189Sjb			va_end(ap);
100179189Sjb			ret_val = _doscan(stdin, nf, newap);
101179189Sjb			free(nf);
102179189Sjb			return(ret_val);
103179189Sjb		}
104179189Sjb		free(nf);
105179189Sjb	} else if (format_arg((unsigned char *)strcpy(newform, fmt), ap, newap)
106179189Sjb	    == ON) {
107179189Sjb		va_end(ap);
108179189Sjb		return(_doscan(iop, newform, newap));
109179189Sjb	}
110179189Sjb	ret_val = _doscan(iop, fmt, ap);
111179189Sjb	va_end(ap);
112179189Sjb	return (ret_val);
113245561Sbrooks}
114179189Sjb
115179189Sjbint
116179189Sjbsscanf(char *str, char *fmt, ...)
117179189Sjb{
118179189Sjb	va_list ap;
119179189Sjb	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
157struct 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
164static int
165format_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