Resolve many build warnings
[oweals/cde.git] / cde / programs / dtksh / ksh93 / src / lib / libast / sfio / sfvprintf.c
1 /*
2  * CDE - Common Desktop Environment
3  *
4  * Copyright (c) 1993-2012, The Open Group. All rights reserved.
5  *
6  * These libraries and programs are free software; you can
7  * redistribute them and/or modify them under the terms of the GNU
8  * Lesser General Public License as published by the Free Software
9  * Foundation; either version 2 of the License, or (at your option)
10  * any later version.
11  *
12  * These libraries and programs are distributed in the hope that
13  * they will be useful, but WITHOUT ANY WARRANTY; without even the
14  * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15  * PURPOSE. See the GNU Lesser General Public License for more
16  * details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with these librararies and programs; if not, write
20  * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21  * Floor, Boston, MA 02110-1301 USA
22  */
23 /* $XConsortium: sfvprintf.c /main/3 1995/11/01 18:38:26 rswiston $ */
24 /***************************************************************
25 *                                                              *
26 *                      AT&T - PROPRIETARY                      *
27 *                                                              *
28 *         THIS IS PROPRIETARY SOURCE CODE LICENSED BY          *
29 *                          AT&T CORP.                          *
30 *                                                              *
31 *                Copyright (c) 1995 AT&T Corp.                 *
32 *                     All Rights Reserved                      *
33 *                                                              *
34 *           This software is licensed by AT&T Corp.            *
35 *       under the terms and conditions of the license in       *
36 *       http://www.research.att.com/orgs/ssr/book/reuse        *
37 *                                                              *
38 *               This software was created by the               *
39 *           Software Engineering Research Department           *
40 *                    AT&T Bell Laboratories                    *
41 *                                                              *
42 *               For further information contact                *
43 *                     gsf@research.att.com                     *
44 *                                                              *
45 ***************************************************************/
46 #include        "sfhdr.h"
47
48 /*      The engine for formatting data
49 **
50 **      Written by Kiem-Phong Vo (06/27/90)
51 */
52
53 #ifdef ulong_hibit
54 #define HIGHBIT         ulong_hibit
55 #else
56 #define HIGHBIT         (~(((ulong)~0L) >> 1))
57 #endif
58
59 #define F_LEFT          000001  /* left justification (-)               */
60 #define F_SIGN          000002  /* must set a sign - or +               */
61 #define F_BLANK         000004  /* if not - and +, then prepend a blank */
62 #define F_ZERO          000010  /* zero padding on the left side        */
63 #define F_ALTER         000020  /* various alternative formats (#)      */
64 #define F_PAD           000040  /* there will be some sort of padding   */
65
66 #define F_REPEAT        000100  /* repeat pattern up to precision       */
67 #define F_MINUS         000200  /* has a minus sign                     */
68 #define F_PREFIX        (F_MINUS|F_SIGN|F_BLANK)
69
70 #define F_LONG          001000  /* object is long                       */
71 #define F_FLOAT         002000  /* %fFeEgG format                       */
72 #define F_GFORMAT       004000  /* a %gG format                         */
73 #define F_LDOUBLE       010000  /* object is long double                */
74
75 #define FPRECIS         6       /* default precision for floats         */
76
77 /* elt:         element to be assigned value.
78 ** arge:        if argf is used, &arge can be passed on to argf to get value.
79 ** argf:        function to get argument if any.
80 ** args:        is the va_list being processed.
81 ** etype:       The type of the element.
82 ** type:        The type of the object (int, double, ...) being gotten out of args.
83 ** fmt:         the format character.
84 ** t_user,n_user: stuff between parens.
85 */
86 #define GETARG(elt,arge,argf,args,etype,type,fmt,t_user,n_user) \
87         { if(!argf) \
88                 elt = (etype)va_arg(args,type); \
89           else if((*argf)(fmt,(char*)(&arge),t_user,n_user) < 0) \
90                 goto pop_fa; \
91           else  elt = (etype)arge; \
92         }
93 #define GETARGL(elt,arge,argf,args,etype,type,fmt,t_user,n_user) \
94         { if(!argf) \
95                 __va_copy( elt, va_arg(args,type) ); \
96           else if((*argf)(fmt,(char*)(&arge),t_user,n_user) < 0) \
97                 goto pop_fa; \
98           else  __va_copy( elt, arge ); \
99         }
100
101 #if __STD_C
102 sfvprintf(Sfio_t* f, const char* form, va_list args)
103 #else
104 sfvprintf(f,form,args)
105 Sfio_t* f;              /* file to print to     */
106 char*   form;           /* format to use        */
107 va_list args;           /* arg list if !argf    */
108 #endif
109 {
110         reg long        n, lval, base;
111         reg char        *sp, *ssp, *d;
112         reg long        v;
113         reg int         flags;
114         reg char        *ep, *endep, *endsp, *endd;
115         reg int         precis, width, n_output, r;
116         int             fmt, sign, decpt, dot;
117         Double_t        dval;   /* could be long double */
118         ulong           along, *alp;
119         uint            aint, *aip;
120         uchar           achar;
121         char*           astr;
122         Argf_p          argf;
123         Extf_p          extf;
124         va_list*        argsp;
125         reg Fa_t        *fa, *fast;
126         char            buf[SF_MAXDIGITS];
127         char            data[SF_GRAIN];
128         char*           t_user; /* stuff between ()     */
129         int             n_user; /* its length           */
130 #if _lib_locale
131         int             dc = 0;
132         struct lconv*   lv;
133 #endif
134
135         /* fast io system */
136 #define SFBUF(f)        (d = (char*)f->next, endd = (char*)f->endb)
137 #define SFINIT(f)       (SFBUF(f), n_output = 0)
138 #define SFEND(f)        ((n_output += (uchar*)d - f->next), (f->next = (uchar*)d))
139 #define SFputc(f,c) \
140         { if(d >= endd) \
141                 { SFEND(f); if(SFFLSBUF(f,c) <  0) break; n_output += 1; SFBUF(f); } \
142           else  { *d++ = (char)c; } \
143         }
144 #define SFnputc(f,c,n) \
145         { if((endd-d) < n) \
146                 { SFEND(f); if(SFNPUTC(f,(int)c,(int)n) != n) break; \
147                   n_output += (int)n; SFBUF(f); } \
148           else  { while(n--) *d++ = (char)c; } \
149         }
150 #define SFwrite(f,s,n) \
151         { if((endd-d) < n) \
152                 { SFEND(f); if(SFWRITE(f,(Void_t*)s,(int)n) != n) break; \
153                   n_output += (int)n; SFBUF(f); } \
154           else  MEMCPY(d,s,(int)n); \
155         }
156
157         /* make sure stream is in write mode and buffer is not NULL */
158         if(f->mode != SF_WRITE && _sfmode(f,SF_WRITE,0) < 0)
159                 return -1;
160
161         SFLOCK(f,0);
162
163         if(!f->data )
164         {       f->data = f->next = (uchar*)data;
165                 f->endw = f->endb = f->data+sizeof(data);
166         }
167         SFINIT(f);
168
169         lval = 0;
170         precis = 0;
171         ep = endep = NIL(char*);
172         argf = NIL(Argf_p);
173         extf = NIL(Extf_p);
174         fast = NIL(Fa_t*);
175
176 loop_fa :
177         while((n = *form++) )
178         {
179                 flags = 0;
180                 if(n != '%')
181                 {       /* collect the non-pattern chars */
182                         sp = ssp = (char*)(form-1);
183                         while((n = *++ssp) && n != '%')
184                                 ;
185                         form = endsp = ssp;
186                         goto do_output;
187                 }
188
189                 t_user = NIL(char*);
190                 n_user = 0;
191                 endep = ep = NIL(char*);
192                 endsp = sp = buf+(sizeof(buf)-1);
193                 width = precis = -1;
194                 dot = 0;
195                 base = 10;
196
197         loop_flags:     /* LOOP FOR FLAGS, WIDTH AND PRECISION */
198 #define LEFTP   '('
199 #define RIGHTP  ')'
200                 switch(fmt = *form++)
201                 {
202                 case LEFTP : /* get the type which is enclosed in balanced () */
203                         t_user = (char*)form;
204                         for(aint = 1;;)
205                         {       switch(*form++)
206                                 {
207                                 case 0 :        /* not balancable, retract */
208                                         form = t_user;
209                                         t_user = NIL(char*);
210                                         n_user = 0;
211                                         goto loop_flags;
212                                 case LEFTP :    /* increasing nested level */
213                                         aint += 1;
214                                         continue;
215                                 case RIGHTP :   /* decreasing nested level */
216                                         if((aint -= 1) != 0)
217                                                 continue;
218                                         n_user = (form-1) - t_user;
219                                         goto loop_flags;
220                                 }
221                         }
222
223                 case '-' :
224                         flags |= F_LEFT;
225                         goto loop_flags;
226                 case ' ' :
227                         flags |= F_BLANK;
228                         goto loop_flags;
229                 case '+' :
230                         flags |= F_SIGN;
231                         goto loop_flags;
232                 case '#' :
233                         flags |= F_ALTER;
234                         goto loop_flags;
235                 case '.' :      /* argument count */
236                         if((dot += 1) > 2)
237                         {       form -= 1;
238                                 continue;
239                         }
240                         goto loop_flags;
241                 case '*' :      /* variable width, precision, or base */
242                         if((dot == 0 && width >= 0) || (dot == 1 && precis >= 0) )
243                         {       form -= 1;      /* bad pattern specification */
244                                 continue;
245                         }
246                         GETARG(lval,aint,argf,args,long,uint,'d',t_user,n_user);
247                         goto set_args;
248                 case '0' :      /* defining width or precision */
249                         if(dot == 0)
250                         {       flags |= F_ZERO;
251                                 goto loop_flags;
252                         }
253                         /* fall thru */
254                 case '1' : case '2' : case '3' :
255                 case '4' : case '5' : case '6' :
256                 case '7' : case '8' : case '9' :
257                         lval = fmt - '0';
258                         for(n = *form; isdigit(n); n = *++form)
259                                 lval = (lval<<3) + (lval<<1) + (n - '0');
260                 set_args:
261                         if(dot == 0)
262                         {       if((width = (int)lval) < 0)
263                                 {       width = -width;
264                                         flags |= F_LEFT;
265                                 }
266                                 flags |= F_PAD;
267                         }
268                         else if(dot == 1)
269                                 precis = (int)lval;
270                         else    base = (int)lval;
271                         goto loop_flags;
272
273                         /* modifier for object's length */
274                 case 'l' :
275                         flags |= F_LONG;
276                         goto loop_flags;
277                 case 'h' :
278                         goto loop_flags;
279                 case 'L' :
280                         flags |= F_LDOUBLE;
281                         goto loop_flags;
282
283                         /* PRINTF DIRECTIVES */
284
285                 case '&' : /* change extension function */
286                         if(!argf)
287                                 extf = va_arg(args,Extf_p);
288                         else if((*argf)('&',(char*)(&extf),t_user,n_user) < 0)
289                                 goto pop_fa;
290                         continue;
291                 case '@' : /* change argument getting function */
292                         if(!argf)
293                                 argf = va_arg(args,Argf_p);
294                         else if((*argf)('@',(char*)(&argf),t_user,n_user) < 0)
295                                 goto pop_fa;
296                         continue;
297                 case ':' : /* stack a pair of format/arglist */
298                         if(!FAMALLOC(fa))
299                                 goto done;
300                         fa->form = (char*)form;
301                         GETARG(form,form,argf,args,char*,char*,'1',t_user,n_user);
302                         if(!form)
303                                 form = "";
304 #if (defined(CSRG_BASED) && !defined(__LP64__)) || (defined(linux) && !defined(__LP64__))
305                         GETARG(argsp,argsp,argf,args,va_list*,va_list*,'2',t_user,n_user);
306                         memcpy((Void_t*)(&(fa->args)), (Void_t*)(&args), sizeof(va_list));
307                         memcpy((Void_t*)(&args), (Void_t*)argsp, sizeof(va_list));
308 #else
309                         GETARGL(argsp,argsp,argf,args,va_list*,va_list*,'2',t_user,n_user);
310                         __va_copy( fa->args, args );
311                         __va_copy( args, argsp );
312 #endif
313                         fa->argf.p = argf;
314                         fa->extf.p = extf;
315                         fa->next = fast;
316                         fast = fa;
317                         continue;
318
319                 default :       /* unknown directive */
320                         if(extf)
321                         {
322 #if defined(CSRG_BASED) && defined(__i386__)
323                                 va_list savarg = args;  /* is this portable? */
324 #else
325                                 va_list savarg;         /* is this portable?   Sorry .. NO. */
326                                 __va_copy( savarg, args );
327 #endif
328
329                                 GETARG(sp,astr,argf,args,char*,char*,fmt,t_user,n_user);
330                                 astr = NIL(char*);
331                                 n = (*extf)(sp,fmt,precis,&astr,(int)base,t_user,n_user);
332                                 if((sp = astr) )
333                                         goto s_format;
334
335 #if defined(CSRG_BASED) && !defined(__LP64__)
336                                 args = savarg;  /* extf failed, treat as if unmatched */
337 #else
338                                 __va_copy( args, savarg ); /* extf failed, treat as if unmatched */
339 #endif
340                         }
341
342                         /* treat as text */
343                         form -= 1;
344                         continue;
345
346                 case 's':       /* a string */
347                         GETARG(sp,astr,argf,args,char*,char*,'s',t_user,n_user);
348                         n = -1;
349                         if(!sp)
350                         {       /* standard error string for null pointer */
351                                 endsp = (sp = "(null)") + 6;
352                                 flags = 0;
353                         }
354                         else
355                         {       /* set other bound */
356                         s_format:
357                                 if(n < 0)
358                                 {       ssp = sp;
359                                         if((n = precis) < 0)
360                                                 while(*ssp++) ;
361                                         else    while(*ssp++ && --n >= 0) ;
362                                         n = (ssp - sp) - 1;
363                                 }
364                                 else if(precis >= 0 && precis < n)
365                                         n = precis;
366                                 endsp = sp+n;
367                         }
368                         flags &= ~(F_SIGN|F_BLANK|F_ALTER);
369                         precis = 0;
370                         break;
371
372                 case 'n':       /* return current output length */
373                         SFEND(f);
374                         if(flags&F_LONG)
375                         {       GETARG(alp,alp,argf,args,
376                                         ulong*,ulong*,'N',t_user,n_user);
377                                 *alp = n_output;
378                         }
379                         else
380                         {       GETARG(aip,aip,argf,args,
381                                         uint*,uint*,'n',t_user,n_user);
382                                 *aip = n_output;
383                         }
384                         continue;
385                 case 'c':       /* a character */
386                         GETARG(fmt,achar,argf,args,int,uint,'c',t_user,n_user);
387                 case '%':
388                         flags = (flags&~(F_SIGN|F_BLANK|F_ZERO))|F_REPEAT;
389                         if(precis <= 0)
390                                 precis = 1;
391                         break;
392                 case 'p':       /* pointer value */
393                         GETARG(ssp,astr,argf,args,char*,char*,'p',t_user,n_user);
394                         lval = (long)ssp;
395                         flags = (flags&~(F_SIGN|F_BLANK|F_ZERO))|F_ALTER;
396                         dot = 0;
397                         fmt = 'x';
398                         goto unsigned_cvt;
399                 case 'o':
400                 case 'x':
401                 case 'X':
402                         dot = 0;
403                 case 'u':
404                         flags &= ~(F_SIGN|F_BLANK);
405                         if(flags&F_LONG)
406                         {       GETARG(lval,along,argf,args,
407                                         long,ulong,'U',t_user,n_user);
408                         }
409                         else
410                         {       GETARG(lval,aint,argf,args,
411                                         long,uint,'u',t_user,n_user); 
412                         }
413                         goto i_format;
414                 case 'i':
415                 case 'd':
416                         if(flags&F_LONG)
417                         {       GETARG(lval,along,argf,args,
418                                         long,long,'D',t_user,n_user);
419                         }
420                         else
421                         {       GETARG(lval,aint,argf,args,
422                                         long,int,'d',t_user,n_user); 
423                         }
424
425                 i_format:
426                         if(lval == 0 && precis == 0)
427                                 goto done_cvt;
428
429                         if(lval < 0 && (fmt == 'd' || fmt == 'i'))
430                         {       flags |= F_MINUS;
431                                 if(lval == HIGHBIT)
432                                 {       /* avoid overflow */
433                                         if(base < 2 || base > SF_RADIX)
434                                                 base = 10;
435                                         lval = ((ulong)HIGHBIT)/base;
436                                         *--sp = _Sfdigits[
437                                                 (ulong)HIGHBIT - ((ulong)lval)*base];
438                                 }
439                                 else    lval = -lval;
440                         }
441
442                 unsigned_cvt:
443                         ssp = _Sfdigits;
444                         switch(fmt)
445                         {
446                         case 'o' :
447                                 base = 8;
448                                 n = 3;
449                                 goto power_cvt;
450                         case 'X' :
451                                 ssp = "0123456789ABCDEF";
452                         case 'x' :
453                                 base = 16;
454                                 n = 4;
455                                 goto power_cvt;
456                         default :
457                                 if(base < 2 || base > SF_RADIX)
458                                         base = 10;
459                                 break;
460                         }
461
462                         if(base == 10)
463                         {       /* special fast conversion for base 10 */
464                                 sfucvt(lval,sp,n,ssp);
465                         }
466                         else if((base & (base-1)) == 0)
467                         {       /* calculate shift amount for power-of-2 base */
468                                 if(base < 8)
469                                         n = base <  4 ? 1 : 2;
470                                 else if(base < 32)
471                                         n = base < 16 ? 3 : 4;
472                                 else    n = base < 64 ? 5 : 6;
473                         power_cvt:
474                                 do
475                                 {       *--sp = ssp[lval&(base-1)];
476                                 } while(lval = ((ulong)lval) >> n);
477                         }
478                         else
479                         {       do
480                                 {       *--sp = ssp[((ulong)lval)%base];
481                                 } while(lval = ((ulong)lval)/((ulong)base));
482                         }
483
484                         /* zero padding for precision */
485                         for(precis -= (endsp-sp); precis > 0; --precis)
486                                 *--sp = '0';
487
488                         if(flags&F_ALTER)
489                         {       /* prefix */
490                                 if(fmt == 'o')
491                                 {       if(*sp != '0')
492                                                 *--sp = '0';
493                                 }
494                                 else
495                                 {       if(width > 0 && (flags&F_ZERO))
496                                         {       /* do 0 padding first */
497                                                 if(dot == 2)
498                                                         n = base < 10 ? 2 : 3;
499                                                 else if(fmt == 'x' || fmt == 'X')
500                                                         n = 0;
501                                                 else    n = width;
502                                                 n += (flags&(F_MINUS|F_SIGN)) ? 1 : 0;
503                                                 n = width - (n + (endsp-sp));
504                                                 while(n-- > 0)
505                                                         *--sp = '0';
506                                         }
507                                         if(dot == 2)
508                                         {       /* base#value notation */
509                                                 *--sp = '#';
510                                                 if(base < 10)
511                                                         *--sp = (char)('0'+base);
512                                                 else
513                                                 {       *--sp = _Sfdec[(base <<= 1)+1];
514                                                         *--sp = _Sfdec[base];
515                                                 }
516                                         }
517                                         else if(fmt == 'x' || fmt == 'X')
518                                         {       *--sp = (char)fmt;
519                                                 *--sp = '0';
520                                         }
521                                 }
522                         }
523
524                 done_cvt:
525                         break;
526
527                 case 'g': /* %g and %G ultimately become %e or %f */
528                 case 'G':
529                 case 'e':
530                 case 'E':
531                 case 'f':
532                 case 'F':
533 #if _typ_long_double
534                         if(flags&F_LDOUBLE)
535                         {       GETARG(dval,dval,argf,args,
536                                         Double_t,Double_t,'G',t_user,n_user);
537                         }
538                         else
539 #endif
540                         {
541 #if _typ_long_double
542                                 double  sdval;
543                                 GETARG(sdval,sdval,argf,args,
544                                         double,double,'F',t_user,n_user);
545                                 dval = sdval;
546 #else
547                                 GETARG(dval,dval,argf,args,
548                                         double,double,'F',t_user,n_user);
549 #endif
550                         }
551
552                         if(fmt == 'e' || fmt == 'E')
553                         {       n = (precis = precis < 0 ? FPRECIS : precis)+1;
554                                 ep = _sfcvt(dval,(int)min(n,SF_FDIGITS),&decpt,&sign,1);
555                                 goto e_format;
556                         }
557                         else if(fmt == 'f' || fmt == 'F')
558                         {       precis = precis < 0 ? FPRECIS : precis;
559                                 ep = _sfcvt(dval,min(precis,SF_FDIGITS),&decpt,&sign,0);
560                                 goto f_format;
561                         }
562
563                         /* 'g' or 'G' format */
564                         precis = precis < 0 ? FPRECIS : precis == 0 ? 1 : precis;
565                         ep = _sfcvt(dval,min(precis,SF_FDIGITS),&decpt,&sign,1);
566                         if(dval == 0.)
567                                 decpt = 1;
568                         else if(*ep == 'I')
569                                 goto infinite;
570
571                         if(!(flags&F_ALTER))
572                         {       /* zap trailing 0s */
573                                 if((n = sfslen()) > precis)
574                                         n = precis;
575                                 while((n -= 1) >= 1 && ep[n] == '0')
576                                         ;
577                                 n += 1;
578                         }
579                         else    n = precis;
580
581                         flags = (flags & ~F_ZERO) | F_GFORMAT;
582                         if(decpt < -3 || decpt > precis)
583                         {       precis = (int)(n-1);
584                                 goto e_format;
585                         }
586                         else
587                         {       precis = (int)(n - decpt);
588                                 goto f_format;
589                         }
590
591                 e_format: /* build the x.yyyy string */
592                         if(isalpha(*ep))
593                                 goto infinite;
594                         sp = endsp = buf+1;     /* reserve space for sign */
595                         *endsp++ = *ep ? *ep++ : '0';
596
597                         if(precis > 0 || (flags&F_ALTER))
598                                 *endsp++ = GETDECIMAL(dc,lv);
599                         ssp = endsp;
600                         endep = ep+precis;
601                         while((*endsp++ = *ep++) && ep <= endep)
602                                 ;
603                         precis -= (endsp -= 1) - ssp;
604
605                         /* build the exponent */
606                         ep = endep = buf+(sizeof(buf)-1);
607                         if(dval != 0.)
608                         {       if((n = decpt - 1) < 0)
609                                         n = -n;
610                                 while(n > 9)
611                                 {       lval = n; n /= 10;      
612                                         *--ep = (char)('0' + (lval - n*10));
613                                 }
614                         }
615                         else    n = 0;
616                         *--ep = (char)('0' + n);
617                         if(endep-ep <= 1)       /* at least 2 digits */
618                                 *--ep = '0';
619
620                         /* the e/Exponent separator and sign */
621                         *--ep = (decpt > 0 || dval == 0.) ? '+' : '-';
622                         *--ep = isupper(fmt) ? 'E' : 'e';
623
624                         flags = (flags&~F_ZERO)|F_FLOAT;
625                         goto end_efg;
626
627                 f_format: /* data before the decimal point */
628                         if(isalpha(*ep))
629                         {
630                         infinite:
631                                 endsp = (sp = ep)+sfslen();
632                                 ep = endep;
633                                 precis = 0;
634                                 goto end_efg;
635                         }
636
637                         endsp = sp = buf+1;     /* save a space for sign */
638                         endep = ep+decpt;
639                         while(ep < endep && (*endsp++ = *ep++))
640                                 ;
641                         if(endsp == sp)
642                                 *endsp++ = '0';
643
644                         if(precis > 0 || (flags&F_ALTER))
645                                 *endsp++ = GETDECIMAL(dc,lv);
646
647                         if((n = -decpt) > 0)
648                         {       /* output zeros for negative exponent */
649                                 ssp = endsp + min(n,precis);
650                                 precis -= (int)n;
651                                 while(endsp < ssp)
652                                         *endsp++ = '0';
653                         }
654
655                         ssp = endsp;
656                         endep = ep+precis;
657                         while((*endsp++ = *ep++) && ep <= endep)
658                                 ;
659                         precis -= (endsp -= 1) - ssp;
660                         ep = endep;
661                         flags |= F_FLOAT;
662                 end_efg:
663                         if(sign)
664                         {       /* if a %gG, output the sign now */
665                                 if(flags&F_GFORMAT)
666                                 {       *--sp = '-';
667                                         flags &= ~(F_SIGN|F_BLANK);
668                                 }
669                                 else    flags |= F_MINUS;
670                         }
671                         break;
672                 }
673
674                 if(!flags)
675                         goto do_output;
676                 else if(flags&(F_MINUS|F_SIGN|F_BLANK))
677                         fmt = (flags&F_MINUS) ? '-' : (flags&F_SIGN) ? '+' : ' ';
678
679                 n = (endsp-sp) + (endep-ep) + (precis <= 0 ? 0 : precis) +
680                     ((flags&F_PREFIX) ? 1 : 0);
681                 if((lval = width-n) > 0)
682                 {       /* check for padding */
683                         if(!(flags&F_ZERO))
684                         {       /* right padding */
685                                 if(flags&F_LEFT)
686                                         lval = -lval;
687                                 else if(flags&F_PREFIX)
688                                 {       /* blank padding, output prefix now */
689                                         *--sp = fmt;
690                                         flags &= ~F_PREFIX;
691                                 }
692                         }
693                 }
694                 else    lval = 0;
695
696                 if(flags&F_PREFIX)
697                 {       /* output prefix */
698                         SFputc(f,fmt);
699                         if(fmt != ' ')
700                                 flags |= F_ZERO;
701                 }
702
703                 if((n = lval) > 0)
704                 {       /* left padding */
705                         v = (flags&F_ZERO) ? '0' : ' ';
706                         SFnputc(f,v,n);
707                 }
708
709                 if((n = precis) > 0 && ((flags&F_REPEAT) || !(flags&F_FLOAT)))
710                 {       /* repeated chars or padding for integer precision */
711                         v = (flags&F_REPEAT) ? fmt : '0';
712                         SFnputc(f,v,n);
713                         precis = 0;
714                 }
715
716         do_output:
717                 if((n = endsp-sp) > 0)
718                         SFwrite(f,sp,n);
719
720                 if(flags&(F_FLOAT|F_LEFT))
721                 {       /* F_FLOAT: right padding for float precision */
722                         if((n = precis) > 0)
723                                 SFnputc(f,'0',n);
724
725                         /* F_FLOAT: the exponent of %eE */
726                         if((n = endep-(sp=ep)) > 0)
727                                 SFwrite(f,sp,n);
728
729                         /* F_LEFT: right padding */
730                         if((n = -lval) > 0)
731                                 SFnputc(f,' ',n);
732                 }
733         }
734
735 pop_fa: if(fa = fast)
736         {       /* pop the format stack and continue */
737                 form = fa->form;
738                 memcpy((Void_t*)(&args), (Void_t*)(&(fa->args)), sizeof(va_list));
739                 argf = fa->argf.p;
740                 extf = fa->extf.p;
741                 fast = fa->next;
742                 FAFREE(fa);
743                 goto loop_fa;
744         }
745
746 done:
747         SFEND(f);
748
749         r = f->next - f->data;
750         if((d = (char*)f->data) == data)
751                 f->endw = f->endr = f->endb = f->data = NIL(uchar*);
752         f->next = f->data;
753
754         if(((f->flags&SF_SHARE) && !(f->flags&SF_PUBLIC)) ||
755            (r > 0 && (d == data || ((f->flags&SF_LINE) && !(f->flags&SF_STRING)))) )
756                 (void)SFWRITE(f,(Void_t*)d,r);
757         else    f->next += r;
758
759         SFOPEN(f,0);
760         return n_output;
761 }