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