xref: /titanic_51/usr/src/lib/libast/common/sfio/sftable.c (revision efd4c9b63ad77503c101fc6c2ed8ba96c9d52964)
1 /***********************************************************************
2 *                                                                      *
3 *               This software is part of the ast package               *
4 *          Copyright (c) 1985-2010 AT&T Intellectual Property          *
5 *                      and is licensed under the                       *
6 *                  Common Public License, Version 1.0                  *
7 *                    by AT&T Intellectual Property                     *
8 *                                                                      *
9 *                A copy of the License is available at                 *
10 *            http://www.opensource.org/licenses/cpl1.0.txt             *
11 *         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         *
12 *                                                                      *
13 *              Information and Software Systems Research               *
14 *                            AT&T Research                             *
15 *                           Florham Park NJ                            *
16 *                                                                      *
17 *                 Glenn Fowler <gsf@research.att.com>                  *
18 *                  David Korn <dgk@research.att.com>                   *
19 *                   Phong Vo <kpv@research.att.com>                    *
20 *                                                                      *
21 ***********************************************************************/
22 #include	"sfhdr.h"
23 #include	"FEATURE/float"
24 
25 /*	Dealing with $ argument addressing stuffs.
26 **
27 **	Written by Kiem-Phong Vo.
28 */
29 
30 #if __STD_C
31 static char* sffmtint(const char* str, int* v)
32 #else
33 static char* sffmtint(str, v)
34 char*	str;
35 int*	v;
36 #endif
37 {
38 	for(*v = 0; isdigit(*str); ++str)
39 		*v = *v * 10 + (*str - '0');
40 	*v -= 1;
41 	return (char*)str;
42 }
43 
44 #if __STD_C
45 static Fmtpos_t* sffmtpos(Sfio_t* f,const char* form,va_list args,Sffmt_t* ft,int type)
46 #else
47 static Fmtpos_t* sffmtpos(f,form,args,ft,type)
48 Sfio_t*		f;
49 char*		form;
50 va_list		args;
51 Sffmt_t*	ft;
52 int		type;	/* >0: scanf, =0: printf, -1: internal	*/
53 #endif
54 {
55 	int		base, fmt, flags, dot, width, precis;
56 	ssize_t		n_str, size;
57 	char		*t_str, *sp;
58 	int		v, n, skip, dollar, decimal, thousand;
59 	Sffmt_t		savft;
60 	Fmtpos_t*	fp;	/* position array of arguments	*/
61 	int		argp, argn, maxp, need[FP_INDEX];
62 #if _has_multibyte
63 	SFMBDCL(fmbs)
64 #endif
65 
66 	if(type < 0)
67 		fp = NIL(Fmtpos_t*);
68 	else if(!(fp = sffmtpos(f,form,args,ft,-1)) )
69 		return NIL(Fmtpos_t*);
70 
71 	dollar = decimal = thousand = 0; argn = maxp = -1;
72 	SFMBCLR(&fmbs);
73 	while((n = *form) )
74 	{	if(n != '%') /* collect the non-pattern chars */
75 		{	sp = (char*)form;
76 			for(;;)
77 			{	form += SFMBLEN(form, &fmbs);
78 				if(*form == 0 || *form == '%')
79 					break;
80 			}
81 			continue;
82 		}
83 		else	form += 1;
84 		if(*form == 0)
85 			break;
86 		else if(*form == '%')
87 		{	form += 1;
88 			continue;
89 		}
90 
91 		if(*form == '*' && type > 0) /* skip in scanning */
92 		{	skip = 1;
93 			form += 1;
94 			argp = -1;
95 		}
96 		else /* get the position of this argument */
97 		{	skip = 0;
98 			sp = sffmtint(form,&argp);
99 			if(*sp == '$')
100 			{	dollar = 1;
101 				form = sp+1;
102 			}
103 			else	argp = -1;
104 		}
105 
106 		flags = dot = 0;
107 		t_str = NIL(char*); n_str = 0;
108 		size = width = precis = base = -1;
109 		for(n = 0; n < FP_INDEX; ++n)
110 			need[n] = -1;
111 
112 	loop_flags:	/* LOOP FOR \0, %, FLAGS, WIDTH, PRECISION, BASE, TYPE */
113 		switch((fmt = *form++) )
114 		{
115 		case LEFTP : /* get the type enclosed in balanced parens */
116 			t_str = (char*)form;
117 			for(v = 1;;)
118 			{	switch(*form++)
119 				{
120 				case 0 :	/* not balancable, retract */
121 					form = t_str;
122 					t_str = NIL(char*);
123 					n_str = 0;
124 					goto loop_flags;
125 				case LEFTP :	/* increasing nested level */
126 					v += 1;
127 					continue;
128 				case RIGHTP :	/* decreasing nested level */
129 					if((v -= 1) != 0)
130 						continue;
131 					n_str = form-t_str;
132 					if(*t_str == '*')
133 					{	t_str = sffmtint(t_str+1,&n);
134 						if(*t_str == '$')
135 							dollar = 1;
136 						else	n = -1;
137 						if((n = FP_SET(n,argn)) > maxp)
138 							maxp = n;
139 						if(fp && fp[n].ft.fmt == 0)
140 						{	fp[n].ft.fmt = LEFTP;
141 							fp[n].ft.form = (char*)form;
142 						}
143 						need[FP_STR] = n;
144 					}
145 					goto loop_flags;
146 				}
147 			}
148 
149 		case '-' :
150 			flags |= SFFMT_LEFT;
151 			flags &= ~SFFMT_ZERO;
152 			goto loop_flags;
153 		case '0' :
154 			if(!(flags&SFFMT_LEFT) )
155 				flags |= SFFMT_ZERO;
156 			goto loop_flags;
157 		case ' ' :
158 			if(!(flags&SFFMT_SIGN) )
159 				flags |= SFFMT_BLANK;
160 			goto loop_flags;
161 		case '+' :
162 			flags |= SFFMT_SIGN;
163 			flags &= ~SFFMT_BLANK;
164 			goto loop_flags;
165 		case '#' :
166 			flags |= SFFMT_ALTER;
167 			goto loop_flags;
168 		case QUOTE:
169 			SFSETLOCALE(&decimal,&thousand);
170 			if(thousand > 0)
171 				flags |= SFFMT_THOUSAND;
172 			goto loop_flags;
173 
174 		case '.' :
175 			if((dot += 1) == 2)
176 				base = 0; /* for %s,%c */
177 			if(isdigit(*form))
178 			{	fmt = *form++;
179 				goto dot_size;
180 			}
181 			else if(*form != '*')
182 				goto loop_flags;
183 			else	form += 1; /* drop thru below */
184 
185 		case '*' :
186 			form = sffmtint(form,&n);
187 			if(*form == '$' )
188 			{	dollar = 1;
189 				form += 1;
190 			}
191 			else	n = -1;
192 			if((n = FP_SET(n,argn)) > maxp)
193 				maxp = n;
194 			if(fp && fp[n].ft.fmt == 0)
195 			{	fp[n].ft.fmt = '.';
196 				fp[n].ft.size = dot;
197 				fp[n].ft.form = (char*)form;
198 			}
199 			if(dot <= 2)
200 				need[dot] = n;
201 			goto loop_flags;
202 
203 		case '1' : case '2' : case '3' :
204 		case '4' : case '5' : case '6' :
205 		case '7' : case '8' : case '9' :
206 		dot_size :
207 			for(v = fmt - '0', fmt = *form; isdigit(fmt); fmt = *++form)
208 				v = v*10 + (fmt - '0');
209 			if(dot == 0)
210 				width = v;
211 			else if(dot == 1)
212 				precis = v;
213 			else if(dot == 2)
214 				base = v;
215 			goto loop_flags;
216 
217 		case 'I' : /* object length */
218 			size = -1; flags = (flags & ~SFFMT_TYPES) | SFFMT_IFLAG;
219 			if(isdigit(*form) )
220 			{	for(size = 0, n = *form; isdigit(n); n = *++form)
221 					size = size*10 + (n - '0');
222 			}
223 			else if(*form == '*')
224 			{	form = sffmtint(form+1,&n);
225 				if(*form == '$' )
226 				{	dollar = 1;
227 					form += 1;
228 				}
229 				else	n = -1;
230 				if((n = FP_SET(n,argn)) > maxp)
231 					maxp = n;
232 				if(fp && fp[n].ft.fmt == 0)
233 				{	fp[n].ft.fmt = 'I';
234 					fp[n].ft.size = sizeof(int);
235 					fp[n].ft.form = (char*)form;
236 				}
237 				need[FP_SIZE] = n;
238 			}
239 			goto loop_flags;
240 
241 		case 'l' :
242 			size = -1; flags &= ~SFFMT_TYPES;
243 			if(*form == 'l')
244 			{	form += 1;
245 				flags |= SFFMT_LLONG;
246 			}
247 			else	flags |= SFFMT_LONG;
248 			goto loop_flags;
249 		case 'h' :
250 			size = -1; flags &= ~SFFMT_TYPES;
251 			if(*form == 'h')
252 			{	form += 1;
253 				flags |= SFFMT_SSHORT;
254 			}
255 			else	flags |= SFFMT_SHORT;
256 			goto loop_flags;
257 		case 'L' :
258 			size = -1; flags = (flags & ~SFFMT_TYPES) | SFFMT_LDOUBLE;
259 			goto loop_flags;
260 		}
261 
262 		/* set object size for scalars */
263 		if(flags & SFFMT_TYPES)
264 		{	if((_Sftype[fmt]&(SFFMT_INT|SFFMT_UINT)) || fmt == 'n')
265 			{	if(flags&SFFMT_LONG)
266 					size = sizeof(long);
267 				else if(flags&SFFMT_SHORT)
268 					size = sizeof(short);
269 				else if(flags&SFFMT_SSHORT)
270 					size = sizeof(char);
271 				else if(flags&SFFMT_TFLAG)
272 					size = sizeof(ptrdiff_t);
273 				else if(flags&SFFMT_ZFLAG)
274 					size = sizeof(size_t);
275 				else if(flags&(SFFMT_LLONG|SFFMT_JFLAG) )
276 					size = sizeof(Sflong_t);
277 				else if(flags&SFFMT_IFLAG)
278 				{	if(size <= 0 ||
279 					   size == sizeof(Sflong_t)*CHAR_BIT )
280 						size = sizeof(Sflong_t);
281 				}
282 				else if(size < 0)
283 					size = sizeof(int);
284 			}
285 			else if(_Sftype[fmt]&SFFMT_FLOAT)
286 			{	if(flags&(SFFMT_LONG|SFFMT_LLONG))
287 					size = sizeof(double);
288 				else if(flags&SFFMT_LDOUBLE)
289 					size = sizeof(Sfdouble_t);
290 				else if(flags&SFFMT_IFLAG)
291 				{	if(size <= 0)
292 						size = sizeof(Sfdouble_t);
293 				}
294 				else if(size < 0)
295 					size = sizeof(float);
296 			}
297 			else if(_Sftype[fmt]&SFFMT_CHAR)
298 			{
299 #if _has_multibyte
300 				if((flags&SFFMT_LONG) || fmt == 'C')
301 				{	size = sizeof(wchar_t) > sizeof(int) ?
302 						sizeof(wchar_t) : sizeof(int);
303 				} else
304 #endif
305 				if(size < 0)
306 					size = sizeof(int);
307 			}
308 		}
309 
310 		if(skip)
311 			continue;
312 
313 		if((argp = FP_SET(argp,argn)) > maxp)
314 			maxp = argp;
315 
316 		if(dollar && fmt == '!')
317 			return NIL(Fmtpos_t*);
318 
319 		if(fp && fp[argp].ft.fmt == 0)
320 		{	fp[argp].ft.form = (char*)form;
321 			fp[argp].ft.fmt = fp[argp].fmt = fmt;
322 			fp[argp].ft.size = size;
323 			fp[argp].ft.flags = flags;
324 			fp[argp].ft.width = width;
325 			fp[argp].ft.precis = precis;
326 			fp[argp].ft.base = base;
327 			fp[argp].ft.t_str = t_str;
328 			fp[argp].ft.n_str = n_str;
329 			for(n = 0; n < FP_INDEX; ++n)
330 				fp[argp].need[n] = need[n];
331 		}
332 	}
333 
334 	if(!fp) /* constructing position array only */
335 	{	if(!dollar || !(fp = (Fmtpos_t*)malloc((maxp+1)*sizeof(Fmtpos_t))) )
336 			return NIL(Fmtpos_t*);
337 		for(n = 0; n <= maxp; ++n)
338 			fp[n].ft.fmt = 0;
339 		return fp;
340 	}
341 
342 	/* get value for positions */
343 	if(ft)
344 		memcpy(&savft, ft, sizeof(*ft));
345 	for(n = 0; n <= maxp; ++n)
346 	{	if(fp[n].ft.fmt == 0) /* gap: pretend it's a 'd' pattern */
347 		{	fp[n].ft.fmt = 'd';
348 			fp[n].ft.width = 0;
349 			fp[n].ft.precis = 0;
350 			fp[n].ft.base = 0;
351 			fp[n].ft.size = 0;
352 			fp[n].ft.t_str = 0;
353 			fp[n].ft.n_str = 0;
354 			fp[n].ft.flags = 0;
355 			for(v = 0; v < FP_INDEX; ++v)
356 				fp[n].need[v] = -1;
357 		}
358 
359 		if(ft && ft->extf)
360 		{	fp[n].ft.version = ft->version;
361 			fp[n].ft.extf = ft->extf;
362 			fp[n].ft.eventf = ft->eventf;
363 			if((v = fp[n].need[FP_WIDTH]) >= 0 && v < n)
364 				fp[n].ft.width = fp[v].argv.i;
365 			if((v = fp[n].need[FP_PRECIS]) >= 0 && v < n)
366 				fp[n].ft.precis = fp[v].argv.i;
367 			if((v = fp[n].need[FP_BASE]) >= 0 && v < n)
368 				fp[n].ft.base = fp[v].argv.i;
369 			if((v = fp[n].need[FP_STR]) >= 0 && v < n)
370 				fp[n].ft.t_str = fp[v].argv.s;
371 			if((v = fp[n].need[FP_SIZE]) >= 0 && v < n)
372 				fp[n].ft.size = fp[v].argv.i;
373 
374 			memcpy(ft,&fp[n].ft,sizeof(Sffmt_t));
375 			va_copy(ft->args,args);
376 			ft->flags |= SFFMT_ARGPOS;
377 			v = (*ft->extf)(f, (Void_t*)(&fp[n].argv), ft);
378 			va_copy(args,ft->args);
379 			memcpy(&fp[n].ft,ft,sizeof(Sffmt_t));
380 			if(v < 0)
381 			{	memcpy(ft,&savft,sizeof(Sffmt_t));
382 				ft = NIL(Sffmt_t*);
383 			}
384 
385 			if(!(fp[n].ft.flags&SFFMT_VALUE) )
386 				goto arg_list;
387 			else if(_Sftype[fp[n].ft.fmt]&(SFFMT_INT|SFFMT_UINT) )
388 			{	if(fp[n].ft.size == sizeof(short))
389 				{	if(_Sftype[fp[n].ft.fmt]&SFFMT_INT)
390 						fp[n].argv.i = fp[n].argv.h;
391 					else	fp[n].argv.i = fp[n].argv.uh;
392 				}
393 				else if(fp[n].ft.size == sizeof(char))
394 				{	if(_Sftype[fp[n].ft.fmt]&SFFMT_INT)
395 						fp[n].argv.i = fp[n].argv.c;
396 					else	fp[n].argv.i = fp[n].argv.uc;
397 				}
398 			}
399 			else if(_Sftype[fp[n].ft.fmt]&SFFMT_FLOAT )
400 			{	if(fp[n].ft.size == sizeof(float) )
401 					fp[n].argv.d = fp[n].argv.f;
402 			}
403 		}
404 		else
405 		{ arg_list:
406 			if(fp[n].ft.fmt == LEFTP)
407 			{	fp[n].argv.s = va_arg(args, char*);
408 				fp[n].ft.size = strlen(fp[n].argv.s);
409 			}
410 			else if(fp[n].ft.fmt == '.' || fp[n].ft.fmt == 'I')
411 				fp[n].argv.i = va_arg(args, int);
412 			else if(fp[n].ft.fmt == '!')
413 			{	if(ft)
414 					memcpy(ft,&savft,sizeof(Sffmt_t));
415 				fp[n].argv.ft = ft = va_arg(args, Sffmt_t*);
416 				if(ft->form)
417 					ft = NIL(Sffmt_t*);
418 				if(ft)
419 					memcpy(&savft,ft,sizeof(Sffmt_t));
420 			}
421 			else if(type > 0) /* from sfvscanf */
422 				fp[n].argv.vp = va_arg(args, Void_t*);
423 			else switch(_Sftype[fp[n].ft.fmt])
424 			{ case SFFMT_INT:
425 			  case SFFMT_UINT:
426 #if !_ast_intmax_long
427 				if(size == sizeof(Sflong_t) )
428 					fp[n].argv.ll = va_arg(args, Sflong_t);
429 				else
430 #endif
431 				if(size == sizeof(long) )
432 					fp[n].argv.l = va_arg(args, long);
433 				else	fp[n].argv.i = va_arg(args, int);
434 				break;
435 			  case SFFMT_FLOAT:
436 #if !_ast_fltmax_double
437 				if(size == sizeof(Sfdouble_t) )
438 					fp[n].argv.ld = va_arg(args,Sfdouble_t);
439 				else
440 #endif
441 					fp[n].argv.d  = va_arg(args,double);
442 				break;
443 	 		  case SFFMT_POINTER:
444 					fp[n].argv.vp = va_arg(args,Void_t*);
445 				break;
446 			  case SFFMT_CHAR:
447 				if(fp[n].ft.base >= 0)
448 					fp[n].argv.s = va_arg(args,char*);
449 #if _has_multibyte
450 				else if((fp[n].ft.flags & SFFMT_LONG) ||
451 					fp[n].ft.fmt == 'C' )
452 				{	if(sizeof(wchar_t) <= sizeof(int) )
453 					     fp[n].argv.wc = (wchar_t)va_arg(args,int);
454 					else fp[n].argv.wc = va_arg(args,wchar_t);
455 				}
456 #endif
457 					/* observe promotion rule */
458 				else	fp[n].argv.i = va_arg(args,int);
459 				break;
460 			  default: /* unknown pattern */
461 				break;
462 			}
463 		}
464 	}
465 
466 	if(ft)
467 		memcpy(ft,&savft,sizeof(Sffmt_t));
468 	return fp;
469 }
470 
471 static const unsigned char	flt_nan[] = { _ast_flt_nan_init };
472 static const unsigned char	flt_inf[] = { _ast_flt_inf_init };
473 static const unsigned char	dbl_nan[] = { _ast_dbl_nan_init };
474 static const unsigned char	dbl_inf[] = { _ast_dbl_inf_init };
475 #ifdef _ast_ldbl_nan_init
476 static const unsigned char	ldbl_nan[] = { _ast_ldbl_nan_init };
477 static const unsigned char	ldbl_inf[] = { _ast_ldbl_inf_init };
478 #endif
479 
480 /* function to initialize conversion tables */
481 static int sfcvinit()
482 {	reg int		d, l;
483 
484 	for(d = 0; d <= SF_MAXCHAR; ++d)
485 	{	_Sfcv36[d] = SF_RADIX;
486 		_Sfcv64[d] = SF_RADIX;
487 	}
488 
489 	/* [0-9] */
490 	for(d = 0; d < 10; ++d)
491 	{	_Sfcv36[(uchar)_Sfdigits[d]] = d;
492 		_Sfcv64[(uchar)_Sfdigits[d]] = d;
493 	}
494 
495 	/* [a-z] */
496 	for(; d < 36; ++d)
497 	{	_Sfcv36[(uchar)_Sfdigits[d]] = d;
498 		_Sfcv64[(uchar)_Sfdigits[d]] = d;
499 	}
500 
501 	/* [A-Z] */
502 	for(l = 10; d < 62; ++l, ++d)
503 	{	_Sfcv36[(uchar)_Sfdigits[d]] = l;
504 		_Sfcv64[(uchar)_Sfdigits[d]] = d;
505 	}
506 
507 	/* remaining digits */
508 	for(; d < SF_RADIX; ++d)
509 	{	_Sfcv36[(uchar)_Sfdigits[d]] = d;
510 		_Sfcv64[(uchar)_Sfdigits[d]] = d;
511 	}
512 
513 	_Sftype['d'] = _Sftype['i'] = SFFMT_INT;
514 	_Sftype['u'] = _Sftype['o'] = _Sftype['x'] = _Sftype['X'] = SFFMT_UINT;
515 	_Sftype['e'] = _Sftype['E'] = _Sftype['a'] = _Sftype['A'] =
516 	_Sftype['g'] = _Sftype['G'] = _Sftype['f'] = SFFMT_FLOAT;
517 	_Sftype['s'] = _Sftype['n'] = _Sftype['p'] = _Sftype['!'] = SFFMT_POINTER;
518 	_Sftype['c'] = SFFMT_CHAR;
519 	_Sftype['['] = SFFMT_CLASS;
520 #if _has_multibyte
521 	_Sftype['S'] = SFFMT_POINTER;
522 	_Sftype['C'] = SFFMT_CHAR;
523 #endif
524 
525 	/* IEEE floating point computed constants */
526 
527 	memcpy((char*)&_Sffnan, (char*)flt_nan, sizeof(_Sffnan));
528 	memcpy((char*)&_Sffinf, (char*)flt_inf, sizeof(_Sffinf));
529 	memcpy((char*)&_Sfdnan, (char*)dbl_nan, sizeof(_Sfdnan));
530 	memcpy((char*)&_Sfdinf, (char*)dbl_inf, sizeof(_Sfdinf));
531 #ifdef _ast_ldbl_nan_init
532 	memcpy((char*)&_Sflnan, (char*)ldbl_nan, sizeof(_Sflnan));
533 	memcpy((char*)&_Sflinf, (char*)ldbl_inf, sizeof(_Sflinf));
534 #else
535 	memcpy((char*)&_Sflnan, (char*)dbl_nan, sizeof(_Sfdnan));
536 	memcpy((char*)&_Sflinf, (char*)dbl_inf, sizeof(_Sfdinf));
537 #endif
538 
539 	return 1;
540 }
541 
542 /* table for floating point and integer conversions */
543 #include	"FEATURE/sfinit"
544