1 /***********************************************************************
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 *
9 * A copy of the License is available at *
10 * http://www.opensource.org/licenses/cpl1.0.txt *
11 * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) *
13 * Information and Software Systems Research *
17 * Glenn Fowler <gsf@research.att.com> *
18 * David Korn <dgk@research.att.com> *
19 * Phong Vo <kpv@research.att.com> *
21 ***********************************************************************/
24 /* The engine for formatting data.
25 ** 1. Argument positioning is done in sftable.c so any changes
26 ** made here should be reflected in sftable.c as well.
27 ** 2. For internationalization, Sfio only supports I/O of multibyte strings.
28 ** However, this code does provide minimal support so that Stdio functions
29 ** such as fwprintf/swprintf can be emulated (see stdvwprintf()).
31 ** Written by Kiem-Phong Vo.
33 #define HIGHBITI (~((~((uint)0)) >> 1))
34 #define HIGHBITL (~((~((Sfulong_t)0)) >> 1))
36 #define SFFMT_PREFIX (SFFMT_MINUS|SFFMT_SIGN|SFFMT_BLANK)
38 #define FPRECIS 6 /* default precision for floats */
43 /* characters when using ebcdic or ascii */
45 #define CC_vt 013 /* vertical tab */
46 #define CC_esc 047 /* escape */
47 #define CC_bel 057 /* bell */
49 #define CC_vt 013 /* vertical tab */
50 #define CC_esc 033 /* escape */
51 #define CC_bel 007 /* bell */
52 #endif /* _chr_ebcdic */
53 #endif /* _PACKAGE_ast */
56 static int chr2str(char* buf
, int v
)
58 static int chr2str(buf
, v
)
63 if(isprint(v
) && v
!= '\\')
70 { case CC_bel
: *buf
++ = 'a'; return 2;
71 case CC_vt
: *buf
++ = 'v'; return 2;
72 case CC_esc
: *buf
++ = 'E'; return 2;
73 case '\b': *buf
++ = 'b'; return 2;
74 case '\f': *buf
++ = 'f'; return 2;
75 case '\n': *buf
++ = 'n'; return 2;
76 case '\r': *buf
++ = 'r'; return 2;
77 case '\t': *buf
++ = 't'; return 2;
78 case '\\': *buf
++ = '\\'; return 2;
79 default: *buf
++ = '0' + ((v
>> 6) & 03);
80 *buf
++ = '0' + ((v
>> 3) & 07);
81 *buf
++ = '0' + ((v
>> 0) & 07);
87 /* On some platform(s), large functions are not compilable.
88 ** In such a case, the below macro should be defined non-zero so that
89 ** some in-lined macros will be made smaller, trading time for space.
91 #if !defined(_sffmt_small) && defined(_UTS)
92 #define _sffmt_small 1
96 int sfvprintf(Sfio_t
* f
, const char* form
, va_list args
)
98 int sfvprintf(f
,form
,args
)
99 Sfio_t
* f
; /* file to print to */
100 char* form
; /* format to use */
101 va_list args
; /* arg list if !argf */
104 int n
, v
, w
, k
, n_s
, base
, fmt
, flags
;
106 char *sp
, *ssp
, *endsp
, *ep
, *endep
;
107 int dot
, width
, precis
, sign
, decpt
;
114 char *tls
[2], **ls
; /* for %..[separ]s */
115 char* t_str
; /* stuff between () */
116 ssize_t n_str
; /* its length */
118 Argv_t argv
; /* for extf to return value */
119 Sffmt_t
*ft
; /* format environment */
120 Fmt_t
*fm
, *fmstk
; /* stack contexts */
122 char* oform
; /* original format string */
123 va_list oargs
; /* original arg list */
124 Fmtpos_t
* fp
; /* arg position list */
125 int argp
, argn
; /* arg position and number */
128 char buf
[SF_MAXDIGITS
+SLACK
], tmp
[SF_MAXDIGITS
+1], data
[SF_GRAIN
];
129 int decimal
= 0, thousand
= 0;
133 SFMBDCL(fmbs
) /* state of format string */
134 SFMBDCL(mbs
) /* state of some string */
141 /* local io system */
143 #define SMputc(f,c) { if((o = SFFLSBUF(f,c)) >= 0 ) n_output += 1; \
144 else { SFBUF(f); goto done; } \
146 #define SMnputc(f,c,n) { if((o = SFNPUTC(f,c,n)) > 0 ) n_output += 1; \
147 if(o != n) { SFBUF(f); goto done; } \
149 #define SMwrite(f,s,n) { if((o = SFWRITE(f,(Void_t*)s,n)) > 0 ) n_output += o; \
150 if(o != n) { SFBUF(f); goto done; } \
152 #if _sffmt_small /* these macros are made smaller at some performance cost */
154 #define SFINIT(f) (n_output = 0)
156 #define SFputc(f,c) SMputc(f,c)
157 #define SFnputc(f,c,n) SMnputc(f,c,n)
158 #define SFwrite(f,s,n) SMwrite(f,s,n)
161 #define SFBUF(f) (d = f->next, endd = f->endb)
162 #define SFINIT(f) (SFBUF(f), n_output = 0)
163 #define SFEND(f) ((n_output += d - f->next), (f->next = d))
164 #define SFputc(f,c) { if(d < endd) { *d++ = (uchar)c; } \
165 else { SFEND(f); SMputc(f,c); SFBUF(f); } \
167 #define SFnputc(f,c,n) { if(d+n <= endd) { while(n--) *d++ = (uchar)(c); } \
168 else { SFEND(f); SMnputc(f,c,n); SFBUF(f); } \
170 #define SFwrite(f,s,n) { if(d+n <= endd) { while(n--) *d++ = (uchar)(*s++); } \
171 else { SFEND(f); SMwrite(f,s,n); SFBUF(f); } \
173 #endif /* _sffmt_small */
177 SFCVINIT(); /* initialize conversion tables */
184 /* make sure stream is in write mode and buffer is not NULL */
185 if(f
->mode
!= SF_WRITE
&& _sfmode(f
,SF_WRITE
,0) < 0)
190 if(!f
->data
&& !(f
->flags
&SF_STRING
))
191 { f
->data
= f
->next
= (uchar
*)data
;
192 f
->endb
= f
->data
+sizeof(data
);
207 SFMBCLR(&fmbs
); /* clear multibyte states to parse the format string */
209 { if(n
!= '%') /* collect the non-pattern chars */
212 { if((n
= SFMBLEN(form
, &fmbs
)) <= 0)
216 } while(*(form
+= n
) && *form
!= '%');
228 size
= width
= precis
= base
= n_s
= argp
= -1;
230 endep
= ep
= NIL(char*);
231 endsp
= sp
= buf
+(sizeof(buf
)-1);
235 loop_flags
: /* LOOP FOR \0, %, FLAGS, WIDTH, PRECISION, BASE, TYPE */
236 switch((fmt
= *form
++) )
245 case LEFTP
: /* get the type enclosed in balanced parens */
250 case 0 : /* not balancable, retract */
255 case LEFTP
: /* increasing nested level */
258 case RIGHTP
: /* decreasing nested level */
262 n_str
= (form
-1)-t_str
;
264 { t_str
= (*_Sffmtintf
)(t_str
+1,&n
);
267 !(fp
= (*_Sffmtposf
)(f
,oform
,oargs
,ft
,0)) )
271 else n
= FP_SET(-1,argn
);
274 { t_str
= fp
[n
].argv
.s
;
275 n_str
= fp
[n
].ft
.size
;
277 else if(ft
&& ft
->extf
)
278 { FMTSET(ft
, form
,args
,
282 (f
,(Void_t
*)&argv
,ft
);
285 if(!(ft
->flags
&SFFMT_VALUE
) )
287 if((t_str
= argv
.s
) &&
288 (n_str
= (int)ft
->size
) < 0)
289 n_str
= strlen(t_str
);
293 if((t_str
= va_arg(args
,char*)) )
294 n_str
= strlen(t_str
);
302 flags
= (flags
& ~(SFFMT_CENTER
|SFFMT_ZERO
)) | SFFMT_LEFT
;
305 if(!(flags
&(SFFMT_LEFT
|SFFMT_CENTER
)) )
309 if(!(flags
&SFFMT_SIGN
) )
310 flags
|= SFFMT_BLANK
;
313 flags
= (flags
& ~SFFMT_BLANK
) | SFFMT_SIGN
;
316 flags
= (flags
& ~(SFFMT_LEFT
|SFFMT_ZERO
)) | SFFMT_CENTER
;
319 flags
|= SFFMT_ALTER
;
322 SFSETLOCALE(&decimal
,&thousand
);
324 flags
|= SFFMT_THOUSAND
;
327 SFSETLOCALE(&decimal
,&thousand
);
330 flags
|= SFFMT_THOUSAND
;
336 { /* so base can be defined without setting precis */
341 { base
= 0; /* for %s,%c */
342 v
= form
[0] == 'l' ? form
[1] : form
[0];
343 if(v
== 'c' || v
== 'C' || v
== 's' || v
== 'S')
345 if(*form
&& !isalnum(*form
))
346 { v
= form
[1] == 'l' ? form
[2] : form
[1];
347 if(v
== 'c' || v
== 'C' || v
== 's' || v
== 'S')
362 else if(*form
!= '*')
365 form
+= 1; /* fall thru for '*' */
367 form
= (*_Sffmtintf
)(form
,&n
);
370 if(!fp
&& !(fp
= (*_Sffmtposf
)(f
,oform
,oargs
,ft
,0)) )
374 else n
= FP_SET(-1,argn
);
378 else if(ft
&& ft
->extf
)
379 { FMTSET(ft
, form
,args
, '.',dot
, 0, 0,0,0, NIL(char*), 0);
380 if((*ft
->extf
)(f
, (Void_t
*)(&argv
), ft
) < 0)
383 flags
= (flags
&~SFFMT_TYPES
) | (ft
->flags
&SFFMT_TYPES
);
384 if(ft
->flags
&SFFMT_VALUE
)
386 else v
= (dot
<= 2) ? va_arg(args
,int) : 0;
388 else v
= dot
<= 2 ? va_arg(args
,int) : 0;
391 case '1' : case '2' : case '3' :
392 case '4' : case '5' : case '6' :
393 case '7' : case '8' : case '9' :
395 for(v
= fmt
- '0'; isdigit(*form
); ++form
)
396 v
= v
*10 + (*form
- '0');
399 if(!fp
&& !(fp
= (*_Sffmtposf
)(f
,oform
,oargs
,ft
,0)) )
406 { if((width
= v
) < 0)
408 flags
= (flags
& ~(SFFMT_CENTER
|SFFMT_ZERO
)) | SFFMT_LEFT
;
417 case 'I' : /* object length */
418 size
= -1; flags
= (flags
& ~SFFMT_TYPES
) | SFFMT_IFLAG
;
420 { for(size
= 0, n
= *form
; isdigit(n
); n
= *++form
)
421 size
= size
*10 + (n
- '0');
423 else if(*form
== '*')
424 { form
= (*_Sffmtintf
)(form
+1,&n
);
428 !(fp
= (*_Sffmtposf
)(f
,oform
,oargs
,ft
,0)))
432 else n
= FP_SET(-1,argn
);
434 if(fp
) /* use position list */
436 else if(ft
&& ft
->extf
)
437 { FMTSET(ft
, form
,args
, 'I',sizeof(int), 0, 0,0,0,
439 if((*ft
->extf
)(f
, (Void_t
*)(&argv
), ft
) < 0)
441 if(ft
->flags
&SFFMT_VALUE
)
443 else size
= va_arg(args
,int);
445 else size
= va_arg(args
,int);
450 size
= -1; flags
&= ~SFFMT_TYPES
;
453 flags
|= SFFMT_LLONG
;
455 else flags
|= SFFMT_LONG
;
458 size
= -1; flags
&= ~SFFMT_TYPES
;
461 flags
|= SFFMT_SSHORT
;
463 else flags
|= SFFMT_SHORT
;
466 size
= -1; flags
= (flags
& ~SFFMT_TYPES
) | SFFMT_LDOUBLE
;
470 size
= -1; flags
= (flags
&~SFFMT_TYPES
) | SFFMT_JFLAG
;
473 size
= -1; flags
= (flags
&~SFFMT_TYPES
) | SFFMT_ZFLAG
;
476 size
= -1; flags
= (flags
&~SFFMT_TYPES
) | SFFMT_TFLAG
;
482 /* set object size for scalars */
483 if(flags
& SFFMT_TYPES
)
484 { if((_Sftype
[fmt
]&(SFFMT_INT
|SFFMT_UINT
)) || fmt
== 'n')
485 { if(flags
&SFFMT_LONG
)
487 else if(flags
&SFFMT_SHORT
)
488 size
= sizeof(short);
489 else if(flags
&SFFMT_SSHORT
)
491 else if(flags
&SFFMT_TFLAG
)
492 size
= sizeof(ptrdiff_t);
493 else if(flags
&SFFMT_ZFLAG
)
494 size
= sizeof(size_t);
495 else if(flags
&(SFFMT_LLONG
|SFFMT_JFLAG
) )
496 size
= sizeof(Sflong_t
);
497 else if(flags
&SFFMT_IFLAG
)
499 size
== sizeof(Sflong_t
)*CHAR_BIT
)
500 size
= sizeof(Sflong_t
);
505 else if(_Sftype
[fmt
]&SFFMT_FLOAT
)
506 { if(flags
&SFFMT_LDOUBLE
)
507 size
= sizeof(Sfdouble_t
);
508 else if(flags
&(SFFMT_LONG
|SFFMT_LLONG
))
509 size
= sizeof(double);
510 else if(flags
&SFFMT_IFLAG
)
512 size
= sizeof(Sfdouble_t
);
515 size
= sizeof(float);
517 else if(_Sftype
[fmt
]&SFFMT_CHAR
)
520 if((flags
&SFFMT_LONG
) || fmt
== 'C')
521 { size
= sizeof(wchar_t) > sizeof(int) ?
522 sizeof(wchar_t) : sizeof(int);
530 argp
= FP_SET(argp
,argn
);
532 { if(ft
&& ft
->extf
&& fp
[argp
].ft
.fmt
!= fp
[argp
].fmt
)
533 fmt
= fp
[argp
].ft
.fmt
;
534 argv
= fp
[argp
].argv
;
535 size
= fp
[argp
].ft
.size
;
537 else if(ft
&& ft
->extf
) /* extended processing */
538 { FMTSET(ft
, form
,args
, fmt
, size
,flags
, width
,precis
,base
,
540 SFEND(f
); SFOPEN(f
,0);
541 v
= (*ft
->extf
)(f
, (Void_t
*)(&argv
), ft
);
542 SFLOCK(f
,0); SFBUF(f
);
544 if(v
< 0) /* no further processing */
546 else if(v
> 0) /* extf output v bytes */
550 else /* extf did not output */
551 { FMTGET(ft
, form
,args
, fmt
, size
,flags
, width
,precis
,base
);
553 if(!(ft
->flags
&SFFMT_VALUE
))
555 else if(_Sftype
[fmt
]&(SFFMT_INT
|SFFMT_UINT
) )
556 { if(size
== sizeof(short))
557 { if(_Sftype
[fmt
]&SFFMT_INT
)
559 else argv
.i
= argv
.uh
;
561 else if(size
== sizeof(char))
562 { if(_Sftype
[fmt
]&SFFMT_INT
)
564 else argv
.i
= argv
.uc
;
567 else if(_Sftype
[fmt
]&SFFMT_FLOAT
)
568 { if(size
== sizeof(float) )
571 else if(_Sftype
[fmt
]&SFFMT_CHAR
)
573 argv
.i
= (int)argv
.c
;
582 #if !_ast_intmax_long
583 if(size
== sizeof(Sflong_t
))
584 argv
.ll
= va_arg(args
, Sflong_t
);
587 if(size
== sizeof(long) )
588 argv
.l
= va_arg(args
, long);
589 else argv
.i
= va_arg(args
, int);
592 #if !_ast_fltmax_double
593 if(size
== sizeof(Sfdouble_t
))
594 argv
.ld
= va_arg(args
,Sfdouble_t
);
597 argv
.d
= va_arg(args
,double);
600 argv
.vp
= va_arg(args
,Void_t
*);
604 argv
.s
= va_arg(args
,char*);
606 else if((flags
& SFFMT_LONG
) || fmt
== 'C')
607 { if(sizeof(wchar_t) <= sizeof(uint
) )
608 argv
.wc
= (wchar_t)va_arg(args
,uint
);
609 else argv
.wc
= va_arg(args
,wchar_t);
612 else argv
.i
= va_arg(args
,int);
614 default: /* unknown pattern */
619 switch(fmt
) /* PRINTF DIRECTIVES */
621 default : /* unknown directive */
626 case '!' : /* stacking a new environment */
628 fp
= (*_Sffmtposf
)(f
,oform
,oargs
,ft
,0);
633 if(!argv
.ft
->form
&& ft
) /* change extension functions */
635 (*ft
->eventf
)(f
,SF_DPOP
,(Void_t
*)form
,ft
) < 0)
637 fmstk
->ft
= ft
= argv
.ft
;
639 else /* stack a new environment */
640 { if(!(fm
= (Fmt_t
*)malloc(sizeof(Fmt_t
))) )
643 ft
= fm
->ft
= argv
.ft
;
644 SFMBSET(ft
->mbs
, &fmbs
);
646 { fm
->form
= (char*)form
; SFMBCPY(&fm
->mbs
,&fmbs
);
647 va_copy(fm
->args
,args
);
650 va_copy(fm
->oargs
,oargs
);
654 form
= ft
->form
; SFMBCLR(ft
->mbs
);
655 va_copy(args
,ft
->args
);
661 else fm
->form
= NIL(char*);
663 fm
->eventf
= ft
->eventf
;
670 flags
= (flags
& ~(SFFMT_TYPES
|SFFMT_LDOUBLE
)) | SFFMT_LONG
;
672 #if _has_multibyte && defined(mbwidth)
673 wc
= (flags
& SFFMT_LDOUBLE
) && mbwide();
675 if(base
>= 0) /* list of strings */
676 { if(!(ls
= argv
.sp
) || !ls
[0])
682 flags
&= ~SFFMT_LONG
;
688 flags
&= ~SFFMT_LONG
;
691 ls
= tls
; tls
[0] = sp
;
694 { /* v: number of bytes w: print width of those v bytes */
696 if(flags
& SFFMT_LONG
)
702 for(n
= 0, wsp
= (wchar_t*)sp
;; ++wsp
, ++n
)
703 { if((size
>= 0 && n
>= size
) ||
704 (size
< 0 && *wsp
== 0) )
706 if((n_s
= wcrtomb(buf
, *wsp
, &mbs
)) <= 0)
710 { n_w
= mbwidth(*wsp
);
711 if(precis
>= 0 && (w
+n_w
) > precis
)
717 if(precis
>= 0 && (v
+n_s
) > precis
)
726 #if _has_multibyte && defined(mbwidth)
732 { if((size
>= 0 && w
>= size
) ||
733 (size
< 0 && *ssp
== 0) )
738 if(precis
>= 0 && (w
+n_w
) > precis
)
749 for(v
= 0; sp
[v
]; ++v
)
752 if(precis
>= 0 && v
> precis
)
757 if((n
= width
- w
) > 0 && !(flags
&SFFMT_LEFT
) )
758 { if(flags
&SFFMT_CENTER
)
769 if(flags
& SFFMT_LONG
)
771 for(wsp
= (wchar_t*)sp
; w
> 0; ++wsp
, --w
)
772 { if((n_s
= wcrtomb(buf
, *wsp
, &mbs
)) <= 0)
774 sp
= buf
; SFwrite(f
, sp
, n_s
);
781 { SFnputc(f
,' ',n
); }
790 flags
= (flags
& ~(SFFMT_TYPES
|SFFMT_LDOUBLE
)) | SFFMT_LONG
;
792 #if _has_multibyte && defined(mbwidth)
793 wc
= (flags
& SFFMT_LDOUBLE
) && mbwide();
795 if(precis
<= 0) /* # of times to repeat a character */
798 if(flags
& SFFMT_LONG
)
800 { if(!(wsp
= (wchar_t*)argv
.s
) )
802 for(size
= 0; wsp
[size
]; ++size
)
813 { if(!(sp
= argv
.s
) )
818 { argv
.c
= (char)(argv
.i
);
829 if((n_s
= wcrtomb(buf
, *wsp
++, &mbs
)) <= 0)
833 n_s
= mbwidth(*(wsp
- 1));
835 n
= width
- precis
*n_s
; /* padding amount */
839 if(flags
&SFFMT_ALTER
)
840 { n_s
= chr2str(buf
, *sp
++);
841 n
= width
- precis
*n_s
;
848 if(n
> 0 && !(flags
&SFFMT_LEFT
) )
849 { if(flags
&SFFMT_CENTER
)
854 { SFnputc(f
, ' ', n
);
859 v
= precis
; /* need this because SFnputc may clear it */
863 { ssp
= buf
; k
= n_s
; SFwrite(f
,ssp
,k
); }
867 if(flags
&SFFMT_ALTER
)
869 { ssp
= buf
; k
= n_s
; SFwrite(f
,ssp
,k
); }
872 { SFnputc(f
, fmt
, v
);
876 { SFnputc(f
,' ',n
); };
878 if((size
-= 1) > 0 && base
> 0)
883 case 'n': /* return current output length */
885 #if !_ast_intmax_long
886 if(size
== sizeof(Sflong_t
) )
887 *((Sflong_t
*)argv
.vp
) = (Sflong_t
)n_output
;
890 if(size
== sizeof(long))
891 *((long*)argv
.vp
) = (long)n_output
;
892 else if(size
== sizeof(short) )
893 *((short*)argv
.vp
) = (short)n_output
;
894 else if(size
== sizeof(uchar
) )
895 *((uchar
*)argv
.vp
) = (uchar
)n_output
;
896 else *((int*)argv
.vp
) = (int)n_output
;
900 case 'p': /* pointer value */
902 base
= 16; n_s
= 15; n
= 4;
903 flags
= (flags
&~(SFFMT_SIGN
|SFFMT_BLANK
|SFFMT_ZERO
))|SFFMT_ALTER
;
905 lv
= (Sflong_t
)((Sfulong_t
)argv
.vp
);
908 v
= (int)((uint
)argv
.vp
);
912 base
= 8; n_s
= 7; n
= 3;
913 flags
&= ~(SFFMT_SIGN
|SFFMT_BLANK
);
916 ssp
= "0123456789ABCDEF";
918 base
= 16; n_s
= 15; n
= 4;
919 flags
&= ~(SFFMT_SIGN
|SFFMT_BLANK
);
923 if((flags
&SFFMT_ALTER
) && base
< 0)
924 { flags
&= ~SFFMT_ALTER
;
931 flags
&= ~(SFFMT_SIGN
|SFFMT_BLANK
);
935 if((flags
&SFFMT_ALTER
) && base
< 0)
936 { flags
&= ~SFFMT_ALTER
;
940 if(base
< 2 || base
> SF_RADIX
)
942 if((base
&(n_s
= base
-1)) == 0)
944 n
= base
< 4 ? 1 : 2;
946 n
= base
< 16 ? 3 : 4;
947 else n
= base
< 64 ? 5 : 6;
949 else n_s
= base
== 10 ? -1 : 0;
952 #if !_ast_intmax_long || _more_long_int || _more_void_int
953 if(size
== sizeof(Sflong_t
))
957 else if(sizeof(long) < sizeof(Sflong_t
) && size
== sizeof(long))
959 lv
= (Sflong_t
)argv
.l
;
960 else lv
= (Sflong_t
)argv
.ul
;
964 { sp
= fmtscale(lv
, scale
);
965 #if _has_multibyte && defined(mbwidth)
971 if(lv
== 0 && precis
== 0)
973 if(lv
< 0 && fmt
== 'd' )
974 { flags
|= SFFMT_MINUS
;
975 if(lv
== HIGHBITL
) /* avoid overflow */
976 { lv
= (Sflong_t
)(HIGHBITL
/base
);
977 *--sp
= _Sfdigits
[HIGHBITL
-
978 ((Sfulong_t
)lv
)*base
];
982 if(n_s
< 0) /* base 10 */
984 sfucvt(lv
,sp
,nv
,ssp
,Sflong_t
,Sfulong_t
);
986 else if(n_s
> 0) /* base power-of-2 */
988 { *--sp
= ssp
[lv
&n_s
];
989 } while((lv
= ((Sfulong_t
)lv
) >> n
) );
991 else /* general base */
993 { *--sp
= ssp
[((Sfulong_t
)lv
)%base
];
994 } while((lv
= ((Sfulong_t
)lv
)/base
) );
998 if(sizeof(short) < sizeof(int) && size
== sizeof(short) )
1000 v
= (int)((short)argv
.i
);
1001 else v
= (int)((ushort
)argv
.i
);
1004 else if(size
== sizeof(char))
1006 v
= (int)((uchar
)argv
.i
);
1010 v
= (int)((signed char)argv
.i
);
1013 v
= -((int)((char)(-argv
.i
)));
1014 else v
= ((int)((char)( argv
.i
)));
1024 { sp
= fmtscale(v
, scale
);
1025 #if _has_multibyte && defined(mbwidth)
1031 if(v
== 0 && precis
== 0)
1033 if(v
< 0 && fmt
== 'd' )
1034 { flags
|= SFFMT_MINUS
;
1035 if(v
== HIGHBITI
) /* avoid overflow */
1036 { v
= (int)(HIGHBITI
/base
);
1037 *--sp
= _Sfdigits
[HIGHBITI
-
1042 if(n_s
< 0) /* base 10 */
1043 { sfucvt(v
,sp
,n
,ssp
,int,uint
);
1045 else if(n_s
> 0) /* base power-of-2 */
1047 { *--sp
= ssp
[v
&n_s
];
1048 } while((v
= ((uint
)v
) >> n
) );
1050 else /* n_s == 0, general base */
1052 { *--sp
= ssp
[((uint
)v
)%base
];
1053 } while((v
= ((uint
)v
)/base
) );
1057 if(n_s
< 0 && (flags
&SFFMT_THOUSAND
) && (n
= endsp
-sp
) > 3)
1060 for(ep
= buf
+SLACK
, endep
= ep
+ n
; ; )
1073 /* zero padding for precision if have room in buffer */
1074 if(precis
> 0 && (precis
-= (endsp
-sp
)) < (sp
-buf
)-64)
1078 if(flags
&SFFMT_ALTER
) /* prefix */
1084 { if(width
> 0 && (flags
&SFFMT_ZERO
))
1085 { /* do 0 padding first */
1086 if(fmt
== 'x' || fmt
== 'X')
1090 else n
= base
< 10 ? 2 : 3;
1091 n
+= (flags
&(SFFMT_MINUS
|SFFMT_SIGN
)) ?
1093 n
= width
- (n
+ (endsp
-sp
));
1097 if(fmt
== 'x' || fmt
== 'X')
1098 { *--sp
= (char)fmt
;
1102 { /* base#value notation */
1105 *--sp
= (char)('0'+base
);
1107 { *--sp
= _Sfdec
[(base
<<= 1)+1];
1108 *--sp
= _Sfdec
[base
];
1116 case 'g': case 'G': /* these ultimately become %e or %f */
1120 #if !_ast_fltmax_double
1121 if(size
== sizeof(Sfdouble_t
) )
1122 { v
= SFFMT_LDOUBLE
;
1133 if(fmt
== 'e' || fmt
== 'E' && (v
|= SFFMT_UPPER
))
1134 { v
|= SFFMT_EFORMAT
;
1135 n
= (precis
= precis
< 0 ? FPRECIS
: precis
)+1;
1136 ep
= _sfcvt(valp
,tmp
+1,sizeof(tmp
)-1, min(n
,SF_FDIGITS
),
1137 &decpt
, &sign
, &n_s
, v
);
1140 else if(fmt
== 'f' || fmt
== 'F' && (v
|= SFFMT_UPPER
))
1141 { precis
= precis
< 0 ? FPRECIS
: precis
;
1142 ep
= _sfcvt(valp
,tmp
+1,sizeof(tmp
)-1, min(precis
,SF_FDIGITS
),
1143 &decpt
, &sign
, &n_s
, v
);
1146 else if(fmt
== 'a' || fmt
== 'A' && (v
|= SFFMT_UPPER
))
1147 { v
|= SFFMT_AFORMAT
;
1149 { if(v
& SFFMT_LDOUBLE
)
1150 precis
= 2*(sizeof(Sfdouble_t
) - 2);
1151 else precis
= 2*(sizeof(double) - 2);
1154 ep
= _sfcvt(valp
,tmp
+1,sizeof(tmp
)-1, min(n
,SF_FDIGITS
),
1155 &decpt
, &sign
, &n_s
, v
);
1157 sp
= endsp
= buf
+1; /* reserve space for sign */
1159 *endsp
++ = fmt
== 'a' ? 'x' : 'X';
1164 else /* 'g' or 'G' format */
1165 { precis
= precis
< 0 ? FPRECIS
: precis
== 0 ? 1 : precis
;
1169 ep
= _sfcvt(valp
,tmp
+1,sizeof(tmp
)-1, min(precis
,SF_FDIGITS
),
1170 &decpt
, &sign
, &n_s
, v
);
1176 if(!(flags
&SFFMT_ALTER
))
1177 { /* zap trailing 0s */
1178 if((n
= n_s
) > precis
)
1180 while((n
-= 1) >= 1 && ep
[n
] == '0')
1186 if(decpt
< -3 || decpt
> precis
)
1191 { precis
= n
- decpt
;
1196 e_format
: /* build the x.yyyy string */
1199 sp
= endsp
= buf
+1; /* reserve space for sign */
1201 *endsp
++ = *ep
? *ep
++ : '0';
1203 SFSETLOCALE(&decimal
,&thousand
);
1204 if(precis
> 0 || (flags
&SFFMT_ALTER
))
1208 while((*endsp
++ = *ep
++) && ep
<= endep
)
1210 precis
-= (endsp
-= 1) - ssp
;
1212 /* build the exponent */
1213 ep
= endep
= buf
+(sizeof(buf
)-1);
1215 { if((n
= decpt
- 1) < 0)
1219 *--ep
= (char)('0' + (v
- n
*10));
1223 *--ep
= (char)('0' + n
);
1224 if(endep
-ep
<= 1) /* at least 2 digits */
1227 /* the e/Exponent separator and sign */
1228 *--ep
= (decpt
> 0 || dval
== 0.) ? '+' : '-';
1229 *--ep
= fmt
== 'a' ? 'p' : fmt
== 'A' ? 'P' :
1230 isupper(fmt
) ? 'E' : 'e';
1234 f_format
: /* data before the decimal point */
1238 flags
&= ~SFFMT_ZERO
;
1239 endsp
= (sp
= ep
)+sfslen();
1245 SFSETLOCALE(&decimal
,&thousand
);
1246 endsp
= sp
= buf
+1; /* save a space for sign */
1248 if(decpt
> 3 && (flags
&SFFMT_THOUSAND
) )
1249 { if((n
= decpt
%3) == 0)
1251 while(ep
< endep
&& (*endsp
++ = *ep
++) )
1252 { if(--n
== 0 && (ep
<= endep
-3) )
1253 { *endsp
++ = thousand
;
1259 { while(ep
< endep
&& (*endsp
++ = *ep
++))
1265 if(precis
> 0 || (flags
&SFFMT_ALTER
))
1268 if((n
= -decpt
) > 0)
1269 { /* output zeros for negative exponent */
1270 ssp
= endsp
+ min(n
,precis
);
1278 while((*endsp
++ = *ep
++) && ep
<= endep
)
1280 precis
-= (endsp
-= 1) - ssp
;
1283 flags
|= SFFMT_FLOAT
;
1285 flags
|= SFFMT_MINUS
;
1289 if(flags
== 0 && width
<= 0)
1292 if(flags
&SFFMT_PREFIX
)
1293 fmt
= (flags
&SFFMT_MINUS
) ? '-' : (flags
&SFFMT_SIGN
) ? '+' : ' ';
1295 n
= (endsp
-sp
) + (endep
-ep
) + (precis
<= 0 ? 0 : precis
) +
1296 ((flags
&SFFMT_PREFIX
) ? 1 : 0);
1297 if((v
= width
-n
) <= 0)
1299 else if(!(flags
&SFFMT_ZERO
)) /* right padding */
1300 { if(flags
&SFFMT_LEFT
)
1302 else if(flags
&SFFMT_PREFIX
) /* blank padding, output prefix now */
1304 flags
&= ~SFFMT_PREFIX
;
1308 if(flags
&SFFMT_PREFIX
) /* put out the prefix */
1311 flags
|= SFFMT_ZERO
;
1314 if((n
= v
) > 0) /* left padding */
1315 { v
= (flags
&SFFMT_ZERO
) ? '0' : ' ';
1319 if((n
= precis
) > 0 && !(flags
&SFFMT_FLOAT
))
1320 { /* padding for integer precision */
1326 if((n
= endsp
-sp
) > 0)
1329 if(flags
&(SFFMT_FLOAT
|SFFMT_LEFT
))
1330 { /* SFFMT_FLOAT: right padding for float precision */
1331 if((n
= precis
) > 0)
1334 /* SFFMT_FLOAT: the exponent of %eE */
1335 if((n
= endep
- (sp
= ep
)) > 0)
1338 /* SFFMT_LEFT: right padding */
1340 { SFnputc(f
,' ',n
); }
1347 fp
= NIL(Fmtpos_t
*);
1349 while((fm
= fmstk
) ) /* pop the format stack and continue */
1351 { if(!form
|| !form
[0])
1352 (*fm
->eventf
)(f
,SF_FINAL
,NIL(Void_t
*),ft
);
1353 else if((*fm
->eventf
)(f
,SF_DPOP
,(Void_t
*)form
,ft
) < 0)
1358 if((form
= fm
->form
) )
1359 { SFMBCPY(&fmbs
,&fm
->mbs
);
1360 va_copy(args
, fm
->args
);
1362 va_copy(oargs
,fm
->oargs
);
1374 while((fm
= fmstk
) )
1376 (*fm
->eventf
)(f
,SF_FINAL
,NIL(Void_t
*),fm
->ft
);
1383 n
= f
->next
- f
->data
;
1384 if((sp
= (char*)f
->data
) == data
)
1385 f
->endw
= f
->endr
= f
->endb
= f
->data
= NIL(uchar
*);
1388 if((((flags
= f
->flags
)&SF_SHARE
) && !(flags
&SF_PUBLIC
) ) ||
1389 (n
> 0 && (sp
== data
|| (flags
&SF_LINE
) ) ) )
1390 (void)SFWRITE(f
,(Void_t
*)sp
,n
);
1394 SFMTXRETURN(f
, n_output
);