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