/* Release 3.00 */

/*-------------------------------------------------------------------------*
*                                                                          *
*  printf.c - formatted output module                                *
*                                                                          *
*  COPYRIGHT (C) 1989 Jensen and Partners. All Rights Reserved             *
*  Written by Simon Knight.                                                *
*                                                                          *
*  COPYRIGHT (C) 1991 Psion PLC. All Rights Reserved                       *
*  Modified by NSM.                                                        *
*                                                                          *
*--------------------------------------------------------------------------*/

#define _USE_CONIO
#include <clib.h>

#define _VPUTC(c) _vputc(c)

_STATIC int   _insert_str(char *s, char c, int num);

_STATIC int  _con_flush(FILE *st);
_STATIC int  _buf_flush(FILE *st);

enum modifier { none,                    /* modifier prefixes */
                shortmod,                /* short integer */
                longmod,                 /* long integer */
                ldmod };                 /* LONGDOUBLE - syntax only */

_STATIC void _vprinter(const char *format, va_list  _v_argptr)
{
    int  n, p, c;
    int  np;
    int  pad;
    int  radix;
    int  pretemp;
    int  width, precision;
    enum modifier mod;                  /* modifier type  */
    int  genflag;
    long  target;
    char  *in_str;
    char _fmt_buf[64], *plist;

    n=0;
    _vp_ret=0;
    while((c=format[n++]) !=0)	  /* main loop to scan format string */
    {
        switch(c)
        {
	    case '%':
		goto arg_eval;		      /* scan format spec */
arg_eval_ret:
#pragma warn(wubd => off)
		n+=p;
#pragma warn(wubd => on)
                break;
            default:                          /* output character */
                _VPUTC(c);
                break;
        }
    }
    return;

arg_eval:
				    /* evaluate and output argument */
    plist=(char *) &format[n];
    p=0;			    /* set local format subscript */
    _upperHex='a';                  /* default PF_HEX digit case */
    genflag=0;			    /* all flags to default */

/***************************************************************************
*   This paragraph reads any flags from the format string. The optimal     *
*   path is for no flags. Multiple flags are permitted.                    *
***************************************************************************/
    c=plist[p++];
    if(c == '%')
    {
        _VPUTC(c);
        goto arg_eval_ret;
    }
    while(c != 0)
    {
        switch(c)
        {
            case '-':
                genflag|=PF_LEFT;
                goto cont;
            case '+':
                genflag|=PF_SIGN;
                goto cont;
            case '\ ':
                genflag|=PF_SPACE;
                goto cont;
            case '#':
                genflag|=PF_HASH;
                goto cont;
            case '0':
                genflag|=PF_ZFLAG;
                goto cont;
            default:
                goto noflag;
         }
cont:
         c=plist[p++];
    }
noflag:
    if((genflag&PF_ZFLAG) && (genflag&PF_LEFT))
        genflag&=(~PF_ZFLAG);
    if((genflag&PF_SIGN) && (genflag&PF_SPACE))
        genflag&=(~PF_SPACE);
/***************************************************************************
*   The next paragraph evaluates any width parameter if present. There is  *
*   no limit on field width apart from integer range.                      *
***************************************************************************/

    width=0;
    while (isdigit(c))
    {
	width *= 10;
	width += c- 0x30;
        c=plist[p++];
    }
    if(c == '*')		    /* _width is argument */
    {
	width = va_arg(_v_argptr, int);
	if(width < 0)
	{
	    width*= -1;
	    genflag|=PF_LEFT;
            genflag&=(~PF_ZFLAG);
	}
        c=plist[p++];
    }

/***************************************************************************
*   The next paragraph evaluates any precision parameter if present.       *
*   Default precisions are set by the data type functions. PF_NOPOINT         *
*   if precision implicitly set to 0. Maximum precison is 32 digits.       *
***************************************************************************/

    precision=0;
    pretemp=0;
    if(c == '.')
    {
        while(isdigit(c=plist[p++]))
        {
            pretemp *= 10;
            pretemp += c - 0x30;
        }
	if(c == '*')			  /* precision is argument */
        {
            pretemp = va_arg(_v_argptr, int);
            c=plist[p++];
        }
        if(pretemp >= 0)
        {
            if(pretemp == 0)		       /* precision explicitly zero */
	        genflag|=PF_NOPOINT;
            else
            {
	        precision=pretemp;		   /* precision non zero */
	        if(precision > 32)
		    precision = 32;
            }
            genflag|=PF_PSET;
        }
    }

/***************************************************************************
*   The next paragraph evaluates any type modifiers present. The optimal   *
*   path is for no modifiers                                               *
***************************************************************************/

    switch(c)
    {
        case 0 :                          /* incomplete spec - return for */
        case '\ ':                        /* literal output */
            _VPUTC('%');
            p=0;
	    goto arg_eval_ret;
        case 'h':
            mod=shortmod;                 /* short integer */
            goto modcont;
        case 'l':
            mod=longmod;                  /* long integer */
            goto modcont;
        case 'L':
            mod=ldmod;                    /* LONGDOUBLE ( no semantics) */
            goto modcont;
        default:
            mod=none;
            break;
modcont:
        c=plist[p++];
        break;
    }

/***************************************************************************
*   The next paragraph is the main switch for data types. Arguments are    *
*   fetched and evaluated by the appropriate conversion function with the  *
*   result in a  buffer. The address of this buffer is passed to the	   *
*   appropriate output section - _int_out, _real_out or _str_out.	   *
***************************************************************************/

    switch(c)
    {
        case 'i':                   /* integer types */
        case 'd':
	    genflag|=PF_IS_SIGNED;
	    radix=10;
	    switch(mod)
            {
                case longmod:
		    target=va_arg(_v_argptr, long);
                    break;
                case shortmod:
		    target= (long) va_arg(_v_argptr, short);
                    break;
                default:
		    target= (long) va_arg(_v_argptr, int);
                    break;
            }
	    goto int_out;
	case 'u':			    /* unsigned */
	    radix=10;
	    goto get_uns;
        case 'o':                           /* octal */
	    genflag|=PF_OCT;
	    radix=8;
            goto get_uns;
do_nptr:
        case 'X':                           /* PF_HEX */
	    genflag|=PF_UPPER;
            _upperHex= 'A';
	case 'x':
	    genflag|=PF_HEX;
	    radix=16;
get_uns:
	    switch(mod)
            {
                case longmod:
		    target=va_arg(_v_argptr, long);
                    break;
                case shortmod:
		    target= (long) (unsigned) va_arg(_v_argptr, short);
                    break;
                default:
		    target= (long) (unsigned) va_arg(_v_argptr, int);
                    break;
            }
	    goto int_out;
int_ret:
            break;
	case 'E':			     /* reals */
	    genflag|=PF_UPPER;		     /* exponent form */
        case 'e':
	    genflag|=PF_EXP;
        case 'f':
	    goto do_real;
        case 'G':
	    genflag|=PF_UPPER;
        case 'g':
	    genflag|=PF_GTYPE;
do_real:
            if(mod == ldmod)
              genflag |= PF_LDMOD;
	    if((precision == 0) && ((genflag&PF_NOPOINT)==0))
		precision=6;
            _v_argptr=_real_out(_v_argptr, genflag, width, precision);
	    break;
        case 'c':                               /* character */
            if(!(genflag&PF_LEFT))
            {
              while(width > 1)
              {
                 _VPUTC(' ');
                 --width;
              }
            }
            _VPUTC(va_arg(_v_argptr, int));
            while(width > 1)
            {
               _VPUTC(' ');
               --width;
            }
	    goto arg_eval_ret;
        case 's':
            genflag&= ~PF_ZFLAG;
            precision=pretemp;
                in_str= (char *)(va_arg(_v_argptr, char *));
            if(in_str)
	        _str_out(in_str, genflag, width, precision);
            break;
        case 'n':
            switch(mod)
            {
                case longmod:
                    *(va_arg(_v_argptr, long *)) = _vp_ret;
                    break;
                default :
                    *(va_arg(_v_argptr, int *)) = _vp_ret;
                    break;
            }
      	    goto arg_eval_ret;
        case 'p':                              /* pointer */
                precision=4;
                mod=none;
                goto do_nptr;
        default:             /* invalid type - return for literal output */
            _VPUTC('%');
            p=0;
	    goto arg_eval_ret;
    }
    goto arg_eval_ret;

/***************************************************************************
*   This paragraph handles precision and format for the integer value	   *
*   now in the form of an ASCIIZ string.                                   *
***************************************************************************/

int_out:

    np=50;
    if(genflag&PF_IS_SIGNED)
        ltoa(target, &_fmt_buf[50], radix);
    else
        ultoa(target, &_fmt_buf[50], radix);
    if(precision == 0)	      /* set default precision */
    {
        if((target == 0) && (genflag&PF_NOPOINT)) {
          np=0;
          if((genflag&PF_SPACE)  && ((genflag&PF_IS_SIGNED)))
            _fmt_buf[np++]='\ ';
          _fmt_buf[np]='\0';
          _justify(_fmt_buf, genflag, width);               /* and ouput */
            goto int_ret;
        }
        precision = 1;
    }

    if((genflag&PF_ZFLAG) && (!(genflag&PF_PSET)))
    {
        precision=width;
        width=0;
        if(((target < 0) || (genflag&PF_SIGN)) && (precision > 0))
          --precision;
    }
    genflag&= ~PF_ZFLAG;
    if((target < 0) && (genflag&PF_IS_SIGNED))
        np++;
    pad = precision - strlen(&_fmt_buf[np]);         /* pad with '0' to precision */
    while(pad > 0)
    {
        _fmt_buf[--np]='0';
        pad--;
    }
    if(genflag&(PF_HEX|PF_OCT))              /* PF_HEX and octal prefix */
    {
        if((genflag&PF_HASH) && (target))
        {
	    if(genflag&PF_HEX)
            {
		if(genflag&PF_UPPER)
                    _fmt_buf[--np]='X';
                else
                    _fmt_buf[--np]='x';
            }
            _fmt_buf[--np]= '0';
        }
    }
    if(genflag&PF_IS_SIGNED)
    {                         /* set +/- */
        if(target >= 0)
        {
            if(genflag&PF_SIGN)             /* leading + required */
                _fmt_buf[--np]= '+';
	    else if(genflag&PF_SPACE)	 /* leading PF_SPACE required */
                _fmt_buf[--np]= ' ';
        }
        else
            _fmt_buf[--np]='-';          /* copy existing PF_SIGN */
    }
    _justify(&_fmt_buf[np], genflag, width);      /* and ouput */
    goto int_ret;


}    /* end of vprinter */


/***************************************************************************
*   This next paragraph handles precision and format for the real value    *
*   now in the form of an ASCCIZ string.                                   *
***************************************************************************/

va_list  _rreal_out(va_list _v_argptr, int flag, int wid, int prec)
{
    char _fmt_buf[64];
    LONGDOUBLE ld;

    if(flag&PF_LDMOD)
      ld=va_arg(_v_argptr, LONGDOUBLE);
    else
      ld=(LONGDOUBLE) va_arg(_v_argptr, double);
    _f_fmt(_fmt_buf, ld, flag, prec);
    _justify(_fmt_buf, flag, wid);
    return(_v_argptr);
}

_STATIC int _insert_str(char *s, char c, int num)
{                                        /* insert characters into string */
    movmem(s, s+num, strlen(s)+1);
    setmem(s, num, c);
    return(num);
}

/***************************************************************************
*   This next function handles far pointer arguments.                      *
***************************************************************************/


char  *_fptoa(unsigned long ptr, char *s)
    {
    int pad;
    unsigned off;

    _upperHex='A';
    ultoa(ptr>>16, s, 16);
    s[4]=0;
    pad=4-strlen(s);
    if(pad > 0)
        _insert_str(s, '0', pad);
    s[4]=':';
    off=(unsigned) ptr;
    ultoa((unsigned long) off, &s[5], 16);
    pad=4-strlen(&s[5]);
    s[9]=0;
    if(pad > 0)
        _insert_str(&s[5], '0', pad);
    _upperHex='a';
    return(s);
    }

char *_f_fmt(char *_fmt_buf, LONGDOUBLE num, int flag, int prec)
{
    int  np, nq;
    char extemp[18], out_str[64];
    int  dec, csign;
    int fd;
    int r, t;
    int round, noround, tzeros;

    np=0;
    nq=0;
    _cvt( num, 18, &dec, &csign, out_str);
    if(abs(dec) > 30)			/* default to exponential form */
	flag|=PF_EXP;
    if(csign)				/* set PF_SIGN */
    	_fmt_buf[np++]='-';
    else if(flag&PF_SIGN)
        _fmt_buf[np++]= '+';		/* leading + */
    else if(flag&PF_SPACE)
	_fmt_buf[np++]= ' ';		/* leading space */
    if(flag&PF_HASH)
	flag&=~PF_NOPOINT; 		/* force decimal point */
    fd=np;

/***************************************************************************
*   This paragraph evaluates whether the exponential form is required and  *
*   copies the first digit of the mantissa and inserts the decimal point   *
*   If the exponent form is not being used, the position of the decimal    *
*   point is calulated and 0s are inserted if necessary.                   *
***************************************************************************/

    if( ((flag&PF_GTYPE) && ((dec > (prec)) || (dec < -4))) || (flag&PF_EXP))
    {
	flag|=PF_EXP;		    /* get first digit and decimal point */
	_fmt_buf[np++]=out_str[nq++];
	if(flag&PF_GTYPE)
	    --prec;
	if(!(flag&PF_NOPOINT))
	    _fmt_buf[np++]=DEC_POINT;
    }
    else
    {
	flag&=~PF_EXP;
        if(dec <= 0)               /* if negative exponent pad */
        {
	    _fmt_buf[np++]='0';
	    if(!(flag&PF_NOPOINT))
            {
                r=dec;
		_fmt_buf[np++]=DEC_POINT;
                while(r++ < 0)
                {
		    if(--prec < 0) {
                        nq=-1; /* dont round */
                        break;
                    }
		    _fmt_buf[np++]='0';
                }
            }
            else
              nq=-1;
        }
        else                           /* positive exponent */
        {
            r=dec;
            while(r-- > 0)
            {
		t=out_str[nq++];
		if(nq > 17)
                    t='0';
		_fmt_buf[np++]= (char) t;
		if(flag&PF_GTYPE)
		{
		    if(prec-- == 0)
		        break;
		}
            }
	    if(!(flag&PF_NOPOINT))
		_fmt_buf[np++]=DEC_POINT;
        }
    }

/***************************************************************************
*   This paragraph copies the digits to the right of the decimal point     *
*   to the limit of precison, padding with 0s if necessary.                *
***************************************************************************/

    noround=FALSE;
    tzeros=FALSE;
    if(!(flag&PF_NOPOINT)) 		    /* copy digits to precision */
    {
	tzeros=TRUE;
	while(prec > 0)
	{
	    if(nq > 17)
            {
                noround=TRUE;
                break;
            }
	    _fmt_buf[np++]=out_str[nq++];
	    prec--;
        }
	if (prec > 0)
        {                                 /* pad to precision if necessary */
	    noround=TRUE;
	    if((!(flag&PF_GTYPE)) || (flag&PF_HASH))
	    {
		while(prec-- > 0)
		{
		    _fmt_buf[np++]='0';
		}
	    }
	}
    }
    _fmt_buf[np]=0;

/***************************************************************************
*   This paragraph rounds the copied number if any digits remain unused.   *
***************************************************************************/

    if(nq != -1) {
      round=out_str[nq];
      if((!noround) && (isdigit(round)))     /* round if any digits remain */
      {
  	r=np-1;
          if(round >= '5')
          {
              while(r >= fd-1)
              {
  		if(_fmt_buf[r] == DEC_POINT)	   /* skip decimal point */
                      r--;
                  if(++_fmt_buf[r] > '9')
                      _fmt_buf[r--]='0';
                  else
                      break;                 /* no carry */
                  if(r < fd)
                  {
  		    if(flag&PF_EXP)	   /* handle high order carry */
                      {
                          _fmt_buf[r+1]='1';
  			++dec;
                      }
                      else
                      {
                          _insert_str(&_fmt_buf[fd], '1', 1);
  			np++;
                      }
                      break;
                  }
              }
          }
      }
    }

    if((tzeros) && (flag&(PF_GTYPE|PF_CPP)) && (!(flag&PF_HASH)))
    {
	while(_fmt_buf[--np] == '0')
	{
	    _fmt_buf[np]=0;
	}
	++np;
    }

/***************************************************************************
*   If required, this paragraph converts the exponent to ASCII string and  *
*   copies it to the target buffer.                                        *
***************************************************************************/

    if((_fmt_buf[np-1] == DEC_POINT) && (!(flag&PF_HASH)))
        --np;
    if((flag&PF_EXP) && ((dec != 1) || (!(flag&PF_GTYPE))))
    {
	if(flag&PF_UPPER)
	    _fmt_buf[np++]='E';
        else
	    _fmt_buf[np++]='e';
        if(--dec < 0)
        {
	    _fmt_buf[np++]='-';
            dec=abs(dec);
        }
        else
	    _fmt_buf[np++]='+';
        itoa(dec, extemp, 10);
        t=strlen(extemp);
        r=2-t;
        if(r < 0 )
	    r=0;
	while(r--)
        {                                  /* insert leading 0s */
	    _fmt_buf[np++]='0';
        }
        r=0;
        while(r < t)
        {
	    _fmt_buf[np++]=extemp[r++];
        }
    }

/***************************************************************************
*   This paragraph terminates the string and calls the function which      *
*   justifies the number within its field width and outputs it.            *
***************************************************************************/
    _fmt_buf[np]=0;
    return(_fmt_buf);
}

void _vp_setbuf(FILE *st, char *buffer)
{
    st->_base=buffer;		
    st->_ptr=buffer;
    st->_size=PF_TEMP_BUF;
    st->_cnt=PF_TEMP_BUF;
    st->_flag|=_F_UBUF;
    st->_flag&=(~_F_RST);
    return;
}

void _vp_freebuf(FILE *st)
{
    st->_size=0;
    st->_cnt=0;
    st->_flag&=(~_F_UBUF);
    return;
}

/*-------------------------------------------------------------------------*
*  printf.c - formatted output to stdout                                   *
*  This function provides formatted output to stdout for a variable        *
*  number of arguments.                                                    *
*--------------------------------------------------------------------------*/

int  printf(const char *format, ...)
{
    va_list _v_argptr;
    int temp_buf, ret;

    temp_buf=0;
    if(stdout->_size == 0)
    {
        char buffer[PF_TEMP_BUF];

        stdout->_flag|=_F_RST;
        _vp_setbuf(stdout, buffer);
        temp_buf=1;
    }
    _vp_flush=_flusher;             /* set output flusher */
    _stream=stdout;
    va_start(_v_argptr, format);     /* initialise argument pointer */
    _vprinter(format, _v_argptr);    /* do it */
    if(temp_buf)
    {
        _flusher(stdout);
        stdout->_flag|=_F_RST;
        _vp_freebuf(stdout);
    }
    else if(stdout->_flag&_F_DEV)
        _flusher(stdout);
    ret=_vp_ret;
    return(ret);                 /* return number of characters output */
}

/*-------------------------------------------------------------------------*
*  cprintf.c - formatted output to console                                 *
*  This function provides formatted output to console for a variable       *
*  number of arguments.                                                    *
*--------------------------------------------------------------------------*/

int  _con_flush(FILE *st)
{
     int n, num;
     char *buf;

     n=0;
     buf=st->_base;
     num=st->_cnt;
     if(num < 0)
         num=0;
     num=st->_size-num;
     while(num-- > 0)
     {
         putch(buf[n++]);
     }
     st->_cnt=st->_size;
     st->_ptr=st->_base;
     return(0);
}

int  cprintf(const char *format, ...)
{

    va_list _v_argptr;
    FILE cst;
    char cbuf[PF_VBSIZE];
    int ret;

    _vp_flush=_con_flush;            /* set output function */
    cst._cnt=PF_VBSIZE;
    cst._size=PF_VBSIZE;
    cst._base=cbuf;
    cst._ptr=cbuf;
    _stream=&cst;
    va_start(_v_argptr, format);     /* initialise argument pointer */
    _vprinter(format, _v_argptr);    /* do it */
    _con_flush(&cst);
    ret=_vp_ret;
    return(ret);                 /* return number of characters output */
}

/*-------------------------------------------------------------------------*
*  sprintf.c - formatted output to buffer                                  *
*  This function provides formatted output to a character buffer for a     *
*  variable number of arguments.                                           *
*--------------------------------------------------------------------------*/

int  _buf_flush(FILE *st)
{
    st->_cnt=st->_size;
    st->_ptr=st->_base;
    return(0);
}

int  sprintf(char *s, const char *format, ...)
{
    va_list _v_argptr;
    FILE sst;
    int ret;

    _vp_flush=_buf_flush;            /* set output function */
    sst._base=s;
    sst._ptr=s;
    sst._cnt=INT_MAX-1;
    sst._size=INT_MAX-1;
    sst._flag=_F_BIN;
    _stream=&sst;
    va_start(_v_argptr, format);     /* initialise argument pointer */
    _vprinter(format, _v_argptr);    /* do it */
    *sst._ptr=0;
    ret=_vp_ret;
    return(ret);                 /* return number of characters output */
}

/*-------------------------------------------------------------------------*
*  fprintf.c - formatted output to stream                                  *
*  This function provides formatted output to stream for a variable        *
*  number of arguments.                                                    *
*--------------------------------------------------------------------------*/

int  fprintf(FILE *st, const char *format, ...)
{
    va_list _v_argptr;
    int temp_buf, ret;

    temp_buf=0;
    if((st->_flag&_F_IN) || (!(st->_flag&_F_WRIT)))
        return(-1);
    if(st->_size == 0)
    {
        char buffer[PF_TEMP_BUF];

        st->_flag|=_F_RST;
        _vp_setbuf(st, buffer);
        temp_buf=1;
    }
    _vp_flush=_flusher;             /* set output function */
    _stream=st; 		     /* initialise file pointer */
    va_start(_v_argptr, format);     /* initialise argument pointer */
    _vprinter(format, _v_argptr);     /* do it */
    if(temp_buf)
    {
        _flusher(st);
        st->_flag|=_F_RST;
        _vp_freebuf(st);
    }
    else if(st->_flag&_F_DEV)
        _flusher(st);
    ret=_vp_ret;
    return(ret);                  /* return number of characters output */
}

/*-------------------------------------------------------------------------*
*  vprintf.c - formatted output to stdout                                  *
*  This function provides formatted output to stdout for a variable        *
*  number of arguments.                                                    *
*--------------------------------------------------------------------------*/

int  vprintf(const char *format, va_list param)
{
    va_list _v_argptr;
    int temp_buf, ret;

    temp_buf=0;
    if(stdout->_size == 0)
    {
        char buffer[PF_TEMP_BUF];

        stdout->_flag|=_F_RST;
        _vp_setbuf(stdout, buffer);
        temp_buf=1;
    }
    _vp_flush=_flusher;            /* set output function  */
    _v_argptr= param;              /* initialise argument pointer */
    _stream=stdout;
    _vprinter(format, _v_argptr);  /* do it */
    if(temp_buf)
    {
        _flusher(stdout);
        stdout->_flag|=_F_RST;
        _vp_freebuf(stdout);
    }
    else if(stdout->_flag&_F_DEV)
        _flusher(stdout);
    ret=_vp_ret;
    return(ret);               /* return number of characters output */
}

/*-------------------------------------------------------------------------*
*  vsprintf.c - formatted output to buffer                                 *
*  This function provides formatted output to a character buffer for a     *
*  variable number of arguments.                                           *
*--------------------------------------------------------------------------*/

int  vsprintf(char *s, const char *format, va_list param)
{
    va_list _v_argptr;
    FILE sst;
    int ret;

    _vp_flush=_buf_flush;               /* set output function */
    sst._base=s;
    sst._ptr=s;
    sst._cnt=INT_MAX-1;
    sst._size=INT_MAX-1;
    sst._flag=_F_BIN;
    _stream=&sst;
    _v_argptr= param;                   /* initialise argument pointer */
    _vprinter(format, _v_argptr);	/* do it */
    *sst._ptr=0;                        /* terminator for output string */
    ret=_vp_ret;
    return(ret);                    /* return number of characters output */
}

/*-------------------------------------------------------------------------*
*  vfprintf.c - formatted output to stream                                 *
*  This function provides formatted output to stream for a variable        *
*  number of arguments.                                                    *
*--------------------------------------------------------------------------*/

int  vfprintf(FILE *st, const char *format, va_list param)
{
    va_list _v_argptr;
    int temp_buf, ret;

    temp_buf=0;
    if((st->_flag&_F_IN) || (!(st->_flag&_F_WRIT)))
        return(-1);
    if(st->_size == 0)
    {
        char buffer[PF_TEMP_BUF];

        st->_flag|=_F_RST;
        _vp_setbuf(st, buffer);
        temp_buf=1;
    }
    _vp_flush=_flusher;            /* set output function */
    _stream=st; 		    /* set file pointer */
    _v_argptr=param;                /* initialise argument pointer */
    _vprinter(format, _v_argptr);   /* do it */
    if(temp_buf)
    {
        char buffer[PF_TEMP_BUF];

        _flusher(st);
        st->_flag|=_F_RST;
        _vp_setbuf(st, buffer);
    }
    else if(st->_flag&_F_DEV)
        _flusher(st);
    ret=_vp_ret;
    return(ret);                /* return number of characters output */
}
