/************************** //
#define printfusefloat TRUE
// **************************/


///////////////////////////////////////////////////
#define formatparams_minus  1
#define formatparams_diez   2
#define formatparams_zero   4
//#define formatparams_plus

#define formatparams_signed 8
#define formatparams_hex    16
#define formatparams_shortlarge  32

//#define formatparams_short  32
//#define formatparams_long  0

#define formatparams_zerominus formatparams_zero|formatparams_minus
///////////////////////////////////////////////////
:int uniformat( int putch, pmask )
static char  buffnum[80];
int   retcode = 0;
byte  flags;
int   prezult;
int   precision;
int   width;
int   bufferlen;
char  buffer[80];
{
  $push (E)BX
  $cld (E)SI = pmask;
#ifdef __FLAT__
  $lodsd
#else
  $lodsw
#endif
  (E)SI >< (E)AX; prezult = (E)AX;

MAINLOOP:
  $lodsb;
  IF( !AL ){ $pop (E)BX; return retcode; }
  IF( AL != '%' ){ PUTCHAR: putch(); retcode++; goto MAINLOOP; }
  bufferlen = flags = 0;
  ANALMASK1:
  $lodsb
//IF( AL == '+' ){ flags |= formatparams_plus ; goto ANALMASK1;}
  IF( AL == '-' ){ flags |= formatparams_minus; goto ANALMASK1;}
  IF( AL == '#' ){ flags |= formatparams_diez ; goto ANALMASK1;}
  IF( AL == '0' ){ flags |= formatparams_zero ; $lodsb }

  $call GETDEC
  width = (E)BX;

  (E)BX=-1;
  IF( AL == '.'  ){ $lodsb $call GETDEC  }
  precision = (E)BX;
//F|N|h|l|L
HL:
  IF( AL == 'l' )
  {
#ifdef __FLAT__
    flags &= !formatparams_shortlarge;
#else
    flags |= formatparams_shortlarge;
#endif
    LHL:
    $lodsb
    GOTO HL;
  }
  IF( AL == 'h' )
  {
#ifdef __FLAT__
    flags |= formatparams_shortlarge;
#else
    flags &= !formatparams_shortlarge;
#endif
    GOTO LHL;
  }
  $push (E)SI

  (E)BX = prezult;

  IF( AL == 'c' )||( AL == 'C' )
  {
    buffnum = DSBYTE[ (E)BX ];
    bufferlen ++;
    (E)SI = #buffnum;
    goto FORMAT2;
  }

  EDX = DSDWORD[ (E)BX ];
#ifdef __FLAT__
  IF($test flags,formatparams_shortlarge ){
    EDX=DX;
    prezult-=2;
  }
#else
  IF(!$test flags,formatparams_shortlarge )EDX=DX;
  else prezult+=2;
#endif
  IF( AL == 's' )
  {
    $push (E)DI
    (E)DI = (E)DX; (E)SI = (E)DI;
    (E)CX = precision; AL = 0;
    bufferlen = (E)CX;
    IF( (E)CX )
    {
      $repnz $scasb
      IF(ZEROFLAG)(E)CX++;
      bufferlen -= (E)CX;
    }
    $pop (E)DI
    goto FORMAT2;
  }
#ifdef printfusefloat
  if(AL=='f'){
   #ifndef __FLAT__
    EDX = DSDWORD [ (E)BX ];
   #endif
    EDX <<= 1;
    IF(CARRYFLAG) flags |= formatparams_signed;
    EAX = 1; CL = AH;
    EAX >< EDX; //EDX = 1
    $rol EAX,8
    CL >< AL;   //CL = exp, AL=0, EAX=mantissa
    CL -= 127;
    IF( !ZEROFLAG )
    {
      IF( signed CL > 0 ){

      //!!!!!!!!!!!!    для слишком больших значений
      IF( CL > 31 )
      {
       (E)SI = "+inf";
       bufferlen=4;
       goto FORMAT2;
      }
      //!!!!!!!!!!!!

        $shld EDX,EAX,CL $shl EAX,CL
      }ELSE{
        -CL; $shrd EAX,EDX,CL $shr EDX,CL
      }
    }
    $push (E)DI,EDX
    (E)DI = precision;
    IF( signed (E)DI < 0 )(E)DI = 6; //default precision 4 float
    $push (E)DI
    LOOPNZ( (E)DI ){
      EBX = EAX;
      DX = 0x3008;
      ECX = 0b11001100110011001100110011001101;//2^32*0.8
      do{
        IF( EBX >= ECX ){
          EBX -= ECX;
          DH|=DL;
        }
        ECX >>= 1;
        DL >>= 1;
      }while( !ZEROFLAG );
      buffnum[ (E)DI-1 ] = DH;//printf("%d",DH);
      EAX *= 10;
    }
    $pop (E)BX,EDX,(E)DI
    IF( (E)BX )||( $test flags, formatparams_diez )
    {
      buffnum[ (E)BX ] = '.';
      (E)BX ++;
    }
    GOTO WRINTCONT;
  }
#endif
  IF( AL == 'x' )||( AL == 'X' )
  {
    flags |= formatparams_hex;
    GOTO WRINT;
  }
  IF( AL == 'u' )
  {
    GOTO WRINT;
  }
  if( AL == 'i' )||( AL == 'd' )
  {
    IF( signed (E)DX < 0 )
    {
      flags |= formatparams_signed;
      -(E)DX;
    }
WRINT:
    AH >< AL;
    (E)BX = 0;
WRINTCONT:
    IF( $test flags, formatparams_hex )
    {
      //hex
      do
      {
        AL = DL&0xF|'0';
        IF( AL > '9' )AL += 'A'-'9'-1;
        IF( AH == 'x' )AL |= 0x20;
        buffnum[ (E)BX ] = AL;
        (E)BX ++;
        EDX >>= 4;
      }while( !ZEROFLAG );//while( (E)DX );
    } ELSE {
      //dec
      do
      {
        EDX >< EAX;
        EAX /= 10;
        EDX >< EAX;
        buffnum[ (E)BX ] = AL+'0';
        (E)BX++ ;
      }while( EDX );
    }
    //общее
    (E)DX = precision;
    IF( flags& formatparams_zerominus == formatparams_zero )
    {
      IF( signed (E)DX < 0 )(E)DX = width;
    }

    WHILE( signed (E)BX < (E)DX )
    {
      buffnum[ (E)BX ] = '0'; (E)BX ++;
    }

    IF( $test flags, formatparams_hex )
    {
      //hex
      IF( $test flags, formatparams_diez )
      {
        buffnum[ (E)BX ] = AH;  (E)BX ++;
        buffnum[ (E)BX ] = '0'; (E)BX ++;
        width += 2;
      }
    } ELSE {
      //dec
      IF( $test flags,formatparams_signed )
      {
        buffnum[(E)BX] = '-'; (E)BX++;
      }
    }
    //общее
    $push (E)DI
    (E)DI = #buffer;
    loop( (E)BX )
    {
      AL = buffnum[ (E)BX-1 ]; $stosb; bufferlen ++;
    }
    $pop (E)DI
    FORMAT:
    (E)SI = #buffer;
    FORMAT2:
    (E)CX = width-bufferlen;
    IF( !$test flags, formatparams_minus )$call EXPAND
    LOOPNZ( bufferlen ){ $lodsb putch(); retcode++; }
    IF( $test flags, formatparams_minus )$call EXPAND
    prezult += sizeof(int);
    $pop (E)SI
    goto MAINLOOP;
  }
  $pop (E)SI
  goto PUTCHAR;

  EXPAND: IF( signed (E)CX > 0 )loop( (E)CX ){ AL=' '; putch(); retcode++; } $ret
  GETDEC: (E)BX = 0;
          WHILE( AL >= '0' )&&( AL <= '9' ) {
            AL -= '0'; (E)BX = 10*(E)BX + (E)AX;
            $lodsb
          }
          $ret
}

:uniwsprintfputc(){ $stosb; }
:cdecl uniwsprintf(int buff,mask,...)
{
  (E)DI=buff; uniformat( #uniwsprintfputc, #mask );
  DSBYTE[ (E)DI ] = 0;
}

:static char buff[1024];
#ifdef __TLS__
:cdecl uniprintf(int mask,...){
  int  retcode;

  (E)DI = #buff;
  WriteFile(
    GetStdHandle(STD_OUTPUT_HANDLE)
   ,#buff
   ,uniformat( #uniwsprintfputc, #mask )
   ,#retcode
   ,0
  );
  return retcode;
}

:int cdecl unicprintf(int mask,...){
  int  retcode;
  (E)DI = #buff;
  WriteConsole(
    GetStdHandle(STD_OUTPUT_HANDLE)
   ,#buff
   ,uniformat( #uniwsprintfputc, #mask )
   ,#retcode
   ,0
  );
  return retcode;
}
#else
:uniprintfputc(){ AL><DL; AH=2; $int 0x21 }
:cdecl uniprintf(int mask,...){ uniformat( #uniprintfputc, #mask ); }

:unicprintfputc(){ AH=0x0E; $int 0x10 }
:cdecl unicprintf(int mask,...){ uniformat( #unicprintfputc, #mask ); }
#endif
