Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Blame | Last modification | View Log | Download | RSS feed

  1. /****************************************************************************
  2. *
  3. *                            Open Watcom Project
  4. *
  5. *    Portions Copyright (c) 1983-2002 Sybase, Inc. All Rights Reserved.
  6. *
  7. *  ========================================================================
  8. *
  9. *    This file contains Original Code and/or Modifications of Original
  10. *    Code as defined in and that are subject to the Sybase Open Watcom
  11. *    Public License version 1.0 (the 'License'). You may not use this file
  12. *    except in compliance with the License. BY USING THIS FILE YOU AGREE TO
  13. *    ALL TERMS AND CONDITIONS OF THE LICENSE. A copy of the License is
  14. *    provided with the Original Code and Modifications, and is also
  15. *    available at www.sybase.com/developer/opensource.
  16. *
  17. *    The Original Code and all software distributed under the License are
  18. *    distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
  19. *    EXPRESS OR IMPLIED, AND SYBASE AND ALL CONTRIBUTORS HEREBY DISCLAIM
  20. *    ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF
  21. *    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR
  22. *    NON-INFRINGEMENT. Please see the License for the specific language
  23. *    governing rights and limitations under the License.
  24. *
  25. *  ========================================================================
  26. *
  27. * Description:  __prtf() - low level string formatter.
  28. *
  29. ****************************************************************************/
  30.  
  31.  
  32. #define __LONG_LONG_SUPPORT__
  33.  
  34. #if !defined( __NETWARE__ ) && !defined( __UNIX__ )
  35.     #define USE_MBCS_TRANSLATION
  36. #endif
  37.  
  38. #include "variety.h"
  39. #ifdef SAFE_PRINTF
  40.     #include "saferlib.h"
  41. #endif
  42. #include "widechar.h"
  43. #include <stdio.h>
  44. #include <stdarg.h>
  45. #include <stdlib.h>
  46. #include <string.h>
  47. #include <ctype.h>
  48. #if defined( __WIDECHAR__ ) || defined( USE_MBCS_TRANSLATION )
  49.     #include <mbstring.h>
  50. #endif
  51. #include "ftos.h"
  52. #include "farsupp.h"
  53. #include "printf.h"
  54. #include "prtscncf.h"
  55. #include "fixpoint.h"
  56. #include "myvalist.h"
  57.  
  58. #define BUF_SIZE    72  /* 64-bit ints formatted as binary can get big */
  59. #define TRUE        1
  60. #define FALSE       0
  61.  
  62. #define PASCAL_STRING           'S'             /* for Novell */
  63. #define WIDE_CHAR_STRING        'S'
  64.  
  65. #if defined( __QNX_386__ )
  66.     /* for use in QNX 32-bit shared library */
  67.     #pragma aux __prtf "_sl_*" far;
  68. #endif
  69.  
  70.  
  71. #if defined( __QNX__ )
  72.     #define EFG_PRINTF __EFG_Format
  73. #else
  74.     #define EFG_PRINTF (*__EFG_printf)
  75. #endif
  76.  
  77. extern FAR_STRING EFG_PRINTF( char *buffer, my_va_list *args, _mbcs_SPECS __SLIB *specs );
  78.  
  79.  
  80. #if defined( __WIDECHAR__ )
  81.     #define _FAR_OTHER_STRING             FAR_ASCII_STRING
  82. #else
  83.     #define _FAR_OTHER_STRING             FAR_UNI_STRING
  84. #endif
  85.  
  86.  
  87. #if defined( __WINDOWS_386__ )
  88.     #ifdef __SW_3S
  89.         #pragma aux slib_callback_t modify [eax edx ecx fs gs];
  90.     #else
  91.         #pragma aux slib_callback_t modify [fs gs];
  92.     #endif
  93. #endif
  94.  
  95.  
  96. /* forward references */
  97. static const CHAR_TYPE *evalflags( const CHAR_TYPE *, SPECS __SLIB * );
  98. static FAR_STRING formstring( CHAR_TYPE *, my_va_list *, SPECS __SLIB *, CHAR_TYPE * );
  99. static const CHAR_TYPE * getprintspecs( const CHAR_TYPE *, my_va_list *, SPECS __SLIB * );
  100. #ifdef USE_MBCS_TRANSLATION
  101. static void write_wide_string( FAR_UNI_STRING str, SPECS *specs,
  102.                                slib_callback_t *out_putc );
  103. static void write_skinny_string( FAR_ASCII_STRING str, SPECS *specs,
  104.                                  slib_callback_t *out_putc );
  105. #endif
  106.  
  107. #ifdef SAFE_PRINTF
  108.     int __F_NAME(__prtf_s,__wprtf_s)
  109. #else
  110.     int __F_NAME(__prtf,__wprtf)
  111. #endif
  112.                             ( void __SLIB *dest,    /* parm for use by out_putc */
  113.                         const CHAR_TYPE *format,    /* pointer to format string */
  114.                         va_list args,               /* pointer to pointer to args*/
  115. #ifdef SAFE_PRINTF
  116.                         const char **msg,           /* rt-constraint message */
  117. #endif
  118.                         slib_callback_t *out_putc ) /* char output routine */
  119. {
  120.     CHAR_TYPE           buffer[ BUF_SIZE ];
  121.     CHAR_TYPE           null_char = '\0';
  122.     CHAR_TYPE           *a;
  123.     FAR_STRING          arg;
  124.     const CHAR_TYPE     *ctl;
  125.     SPECS               specs;
  126.  
  127.     specs._dest = dest;
  128.     specs._flags = 0;
  129.     specs._version = SPECS_VERSION;
  130.     specs._output_count = 0;
  131.     ctl = format;
  132.     while( *ctl != NULLCHAR ) {
  133.         if( *ctl != '%' ) {
  134.             (out_putc)( &specs, *ctl++ );
  135.         } else {
  136.             ++ctl;
  137.             {
  138.                 my_va_list  pargs;
  139.                 pargs = MY_VA_LIST( args );
  140.                 ctl = getprintspecs( ctl, &pargs, &specs );
  141.                 MY_VA_LIST( args ) = pargs;
  142.             }
  143.  
  144.             specs._character = *ctl++;
  145.             if( specs._character == NULLCHAR )
  146.                 break;        /* 05-jan-89 */
  147.  
  148.             if( specs._character == 'n' ) {
  149. #ifdef SAFE_PRINTF
  150.                 /* The %n specifier is not allowed - too dangerous. */
  151.                 *msg = "%n";
  152.                 break;
  153. #else
  154.                 FAR_INT         iptr;
  155.  
  156. #if defined( __FAR_SUPPORT__ )
  157.                 if( specs._flags & SPF_FAR ) {
  158.                     iptr = va_arg( args, int _WCFAR * );
  159.                 } else if( specs._flags & SPF_NEAR ) {
  160.                     iptr = va_arg( args, int _WCNEAR * );
  161.                 } else {
  162.                     iptr = va_arg( args, int * );
  163.                 }
  164. #else
  165.                 iptr = va_arg( args, int * );
  166. #endif
  167.                 if( specs._flags & SPF_CHAR ) {
  168.                     *((FAR_CHAR)iptr) = specs._output_count;
  169.                 } else if( specs._flags & SPF_SHORT ) {
  170.                     *((FAR_SHORT)iptr) = specs._output_count;
  171.                 } else if( specs._flags & SPF_LONG ) {
  172.                     *((FAR_LONG)iptr) = specs._output_count;
  173. #if defined( __LONG_LONG_SUPPORT__ )
  174.                 } else if( specs._flags & SPF_LONG_LONG ) {
  175.                     *((FAR_INT64)iptr) = specs._output_count;
  176. #endif
  177.                 } else {
  178.                     *iptr = specs._output_count;
  179.                 }
  180. #endif  /* SAFE_PRINTF */
  181.             } else {
  182. #ifdef SAFE_PRINTF
  183.                 if( specs._character == 's' || specs._character == 'S' ) {
  184.                     FAR_STRING  str;
  185.                     va_list     args_copy;
  186.  
  187.                     /* Make sure %s argument is not NULL. Note that near pointers
  188.                      * in segmented models need special handling because only
  189.                      * offset will be NULL, not segment.
  190.                      */
  191.                     va_copy( args_copy, args );
  192. #if defined( __FAR_SUPPORT__ )
  193.                     if( specs._flags & SPF_FAR ) {
  194.                         str = va_arg( args_copy, CHAR_TYPE _WCFAR * );
  195.                     } else if( specs._flags & SPF_NEAR ) {
  196.                         CHAR_TYPE _WCNEAR   *ptr;
  197.  
  198.                         ptr = va_arg( args_copy, CHAR_TYPE _WCNEAR * );
  199.                         if( ptr == NULL ) {
  200.                             str = NULL;
  201.                         } else {
  202.                             str = ptr;
  203.                         }
  204.                     } else {
  205.                         CHAR_TYPE   *ptr;
  206.  
  207.                         ptr = va_arg( args_copy, CHAR_TYPE * );
  208.                         if( ptr == NULL ) {
  209.                             str = NULL;
  210.                         } else {
  211.                             str = ptr;
  212.                         }
  213.                     }
  214. #else
  215.                     str = va_arg( args_copy, CHAR_TYPE * );
  216. #endif
  217.                     va_end( args_copy );
  218.                     if( str == NULL ) {
  219.                         *msg = "%s -> NULL";
  220.                         break;  /* bail out */
  221.                     }
  222.                 }
  223. #endif  /* SAFE_PRINTF */
  224.  
  225.                 {
  226.                     my_va_list  pargs;
  227.                     pargs = MY_VA_LIST( args );
  228.                     arg = formstring( buffer, &pargs, &specs, &null_char );
  229.                     MY_VA_LIST( args ) = pargs;
  230.                 }
  231.                 specs._fld_width -= specs._n0  +
  232.                                     specs._nz0 +
  233.                                     specs._n1  +
  234.                                     specs._nz1 +
  235.                                     specs._n2  +
  236.                                     specs._nz2;
  237.                 if( !(specs._flags & SPF_LEFT_ADJUST) ) {
  238.                     if( specs._pad_char == ' ' ) {
  239.                         while( specs._fld_width > 0 ) {
  240.                             (out_putc)( &specs, ' ' );
  241.                             --specs._fld_width;
  242.                         }
  243.                     }
  244.                 }
  245.                 a = buffer;
  246.                 while( specs._n0 > 0 ) {
  247.                     (out_putc)( &specs, *a );
  248.                     ++a;
  249.                     --specs._n0;
  250.                 }
  251.                 while( specs._nz0 > 0 ) {
  252.                     (out_putc)( &specs, '0' );
  253.                     --specs._nz0;
  254.                 }
  255.                 if( specs._character == 's' ) {
  256. #if defined( __WIDECHAR__ ) && defined( USE_MBCS_TRANSLATION )
  257.                     if( specs._flags & SPF_SHORT ) {
  258.                         write_skinny_string( (FAR_ASCII_STRING)arg, &specs, out_putc );
  259.                     } else
  260. #elif !defined( __WIDECHAR__ ) && defined( USE_MBCS_TRANSLATION )
  261.                     if( specs._flags & SPF_LONG ) {
  262.                         write_wide_string( (FAR_UNI_STRING)arg, &specs, out_putc );
  263.                     } else
  264. #endif
  265.                     {
  266.                         while( specs._n1 > 0 ) {
  267.                             (out_putc)( &specs, *arg++ );
  268.                             --specs._n1;
  269.                         }
  270.                     }
  271.                 }
  272. #if !defined( __WIDECHAR__ ) && defined( USE_MBCS_TRANSLATION )
  273.                 else if( specs._character == WIDE_CHAR_STRING ) {
  274.                     write_wide_string( (FAR_UNI_STRING)arg, &specs, out_putc );
  275.                 } else
  276. #elif !defined( __WIDECHAR__ ) && defined( __NETWARE__ )
  277.                 else if( specs._character == WIDE_CHAR_STRING ) {
  278.                 } else
  279. #endif
  280.                 {
  281.                     while( specs._n1 > 0 ) {
  282.                         (out_putc)( &specs, *arg++ );
  283.                         --specs._n1;
  284.                     }
  285.                 }
  286.                 while( specs._nz1 > 0 ) {
  287.                     (out_putc)( &specs, '0' );
  288.                     --specs._nz1;
  289.                 }
  290.                 while( specs._n2 > 0 ) {
  291.                     (out_putc)( &specs, *arg );
  292.                     ++arg;
  293.                     --specs._n2;
  294.                 }
  295.                 while( specs._nz2 > 0 ) {
  296.                     (out_putc)( &specs, '0' );
  297.                     --specs._nz2;
  298.                 }
  299.                 if( specs._flags & SPF_LEFT_ADJUST ) {
  300.                     while( specs._fld_width > 0 ) {
  301.                         (out_putc)( &specs, ' ' );
  302.                         --specs._fld_width;
  303.                     }
  304.                 }
  305.             }
  306.         }
  307.     }
  308.     return( specs._output_count );
  309. }
  310.  
  311. static const CHAR_TYPE * getprintspecs( const CHAR_TYPE *ctl,
  312.                                         my_va_list *pargs,
  313.                                         SPECS __SLIB *specs )
  314. {
  315.     specs->_pad_char = ' ';
  316.     ctl = evalflags( ctl, specs );
  317.     specs->_fld_width = 0;
  318.     if( *ctl == '*' ) {
  319.         specs->_fld_width = va_arg( pargs->v, int );
  320.         if( specs->_fld_width < 0 ) {
  321.             specs->_fld_width = - specs->_fld_width;
  322.             specs->_flags |= SPF_LEFT_ADJUST;
  323.         }
  324.         ctl++;
  325.     } else {
  326.         while(( *ctl >= '0' ) && ( *ctl <= '9' )) {
  327.             specs->_fld_width = specs->_fld_width * 10 + ( *ctl++ - '0' );
  328.         }
  329.     }
  330.     specs->_prec = -1;
  331.     if( *ctl == '.' ) {
  332.         specs->_prec = 0;
  333.         ctl++;
  334.         if( *ctl == '*' ) {
  335.             specs->_prec = va_arg( pargs->v, int );
  336.             if( specs->_prec < 0 )
  337.                 specs->_prec = -1;    /* 19-jul-90 */
  338.             ctl++;
  339.         } else {
  340.             while(( *ctl >= '0' ) && ( *ctl <= '9' )) {
  341.                 specs->_prec = specs->_prec * 10 + ( *ctl++ - '0' );
  342.             }
  343.         }
  344.         /*
  345.         "For b, d, i, o, u, x, X, e, E, f, g and G conversions, leading
  346.         zeros (following any indication of sign or base) are used to
  347.         pad the field width; no space padding is performed. If the 0
  348.         or - flags both appear, the 0 flag is ignored.  For b, d, i, o,
  349.         u, x or X conversions, if a precision is specified, the 0 flag
  350.         is ignored. For other conversions, the behaviour is undefined."
  351.         */
  352. //      if( specs->_prec != -1 )  specs->_pad_char = ' '; /* 30-jul-95 *//*removed by JBS*/
  353.     }
  354.     switch( *ctl ) {
  355.     case 'l':
  356. #if defined( __LONG_LONG_SUPPORT__ )
  357.         if( ctl[1] == 'l' ) {
  358.             specs->_flags |= SPF_LONG_LONG;
  359.             ctl += 2;
  360.             break;
  361.         }
  362. #endif
  363.         /* fall through */
  364.     ZSPEC_CASE_LONG
  365.     TSPEC_CASE_LONG
  366.     case 'w':
  367.         specs->_flags |= SPF_LONG;
  368.         ctl++;
  369.         break;
  370.     case 'h':
  371.         if( ctl[1] == 'h' ) {
  372.             specs->_flags |= SPF_CHAR;
  373.             ctl += 2;
  374.             break;
  375.         }
  376.         specs->_flags |= SPF_SHORT;
  377.         ctl++;
  378.         break;
  379. #if defined( __LONG_LONG_SUPPORT__ )
  380.     case 'I':
  381.         if(( ctl[1] == '6' ) && ( ctl[2] == '4' )) {
  382.             specs->_flags |= SPF_LONG_LONG;
  383.             ctl += 3;
  384.         }
  385.         break;
  386.     JSPEC_CASE_LLONG
  387.         /* fall through */
  388. #endif
  389.     case 'L':
  390.         specs->_flags |= SPF_LONG_DOUBLE | SPF_LONG_LONG;
  391.         ctl++;
  392.         break;
  393. #if defined( __FAR_SUPPORT__ )
  394.     case 'F':                   /* conflicts with ISO-defined 'F' conversion */
  395.         /* fall through */
  396. #endif
  397.     case 'W':                   /* 8086 specific flag for FAR pointer */
  398.         specs->_flags |= SPF_FAR;
  399.         ctl++;
  400.         break;
  401.     case 'N':                   /* 8086 specific flag for NEAR pointer */
  402.         specs->_flags |= SPF_NEAR;
  403.         ctl++;
  404.         break;
  405. #if defined( TSPEC_IS_INT ) || defined( ZSPEC_IS_INT )
  406.     TSPEC_CASE_INT      /* If either 't' or 'z' spec corresponds to 'int',  */
  407.     ZSPEC_CASE_INT      /* we need to parse and ignore the spec.            */
  408.         ctl++;
  409.         break;
  410. #endif
  411.     }
  412.     return( ctl );
  413. }
  414.  
  415.  
  416. static const CHAR_TYPE *evalflags( const CHAR_TYPE *ctl, SPECS __SLIB *specs )
  417. {
  418.     specs->_flags = 0;
  419.     for( ; ; ctl++ ) {
  420.         if( *ctl == '-' ) {
  421.             specs->_flags |= SPF_LEFT_ADJUST;
  422.         } else if( *ctl == '#' ) {
  423.             specs->_flags |= SPF_ALT;
  424.         } else if( *ctl == '+' ) {
  425.             specs->_flags |= SPF_FORCE_SIGN;
  426.             specs->_flags &= ~SPF_BLANK;
  427.         } else if( *ctl == ' ' ) {
  428.             if( ( specs->_flags & SPF_FORCE_SIGN ) == 0 ) {
  429.                 specs->_flags |= SPF_BLANK;
  430.             }
  431.         } else if( *ctl == '0' ) {
  432.             specs->_pad_char = '0';
  433. #ifdef __QNX__
  434.             specs->_flags |= SPF_ZERO_PAD;
  435. #endif
  436.         } else {
  437.             break;
  438.         }
  439.     }
  440.     return( ctl );
  441. }
  442.  
  443.  
  444. static int far_strlen( FAR_STRING s, int precision )
  445. {
  446.     int     len;
  447.  
  448.     len = 0;
  449.     while(( len != precision ) && ( *s++ != NULLCHAR ))
  450.         ++len;
  451.  
  452.     return( len );
  453. }
  454.  
  455. /*
  456.  * far_other_strlen - calculates the length of an ascii string
  457.  *                    for the unicode version
  458.  *                  - calculates the length of a unicode string for
  459.  *                    the standard version
  460.  */
  461.  
  462. static int far_other_strlen( FAR_STRING s, int precision )
  463. {
  464.     int                 len = 0;
  465.     _FAR_OTHER_STRING   ptr = (_FAR_OTHER_STRING)s;
  466.  
  467. #if !defined( __WIDECHAR__ ) && defined( USE_MBCS_TRANSLATION )
  468.     char                mbBuf[MB_CUR_MAX];
  469.     int                 chBytes;
  470.  
  471.     if( precision == -1 ) {
  472.         while( *ptr ) {
  473.             chBytes = wctomb( mbBuf, *ptr++ );
  474.             if( chBytes != -1 ) {
  475.                 len += chBytes;
  476.             }
  477.         }
  478.         return( len );
  479.     }
  480.     while( *ptr && ( len <= precision )) {
  481.         chBytes = wctomb( mbBuf, *ptr++ );
  482.         if( chBytes != -1 ) {
  483.             len += chBytes;
  484.         }
  485.     }
  486.     return(( len <= precision ) ? len : precision );
  487.  
  488. #else
  489.  
  490.     while( *ptr++ && ( len != precision ))
  491.         ++len;
  492.  
  493.     return( len );
  494. #endif
  495. }
  496.  
  497. static void fmt4hex( unsigned value, CHAR_TYPE *buf, int maxlen )
  498. {
  499.     int     i, len;
  500.  
  501.     __F_NAME(itoa,_itow)( value, buf, 16 );
  502.     len = __F_NAME(strlen,wcslen)( buf );
  503.     for( i = maxlen - 1; len; --i ) {
  504.         --len;
  505.         buf[i] = buf[len];
  506.     }
  507.     while( i >= 0 ) {
  508.         buf[i] = '0';
  509.         --i;
  510.     }
  511.     buf[maxlen] = NULLCHAR;
  512. }
  513.  
  514.  
  515. static void FixedPoint_Format( CHAR_TYPE *buf, long value, SPECS __SLIB *specs )
  516. {
  517.     T32         at;
  518.     int         i;
  519.     CHAR_TYPE   *bufp;
  520.  
  521.     at.sWhole = value;
  522.     if( at.sWhole < 0 ) {
  523.         at.sWhole = - at.sWhole;
  524.         *buf++ = '-';
  525.     }
  526.     if( specs->_prec == -1 )
  527.         specs->_prec = 4;
  528.  
  529.     __F_NAME(itoa,_itow)( at.wd.hi, buf, 10 );
  530.     bufp = buf;         /* remember start address of buffer */
  531.     while( *buf )
  532.         ++buf;
  533.  
  534.     if( specs->_prec != 0 ) {
  535.         *buf++ = '.';
  536.         for( i = 0; i < specs->_prec; i++ ) {
  537.             at.wd.hi = 0;
  538.             at.uWhole *= 10;
  539.             *buf++ = at.bite.b3 + '0';
  540.         }
  541.         *buf = NULLCHAR;
  542.     }
  543.     if( at.wd.lo & 0x8000 ) {   /* fraction >= .5, need to round */
  544.         for(;;) {                               /* 22-dec-91 */
  545.             if( buf == bufp ) {
  546.                 *buf++ = '1';
  547.                 while( *buf == '0' )
  548.                     ++buf;
  549.  
  550.                 if( *buf == '.' ) {
  551.                     *buf++ = '0';
  552.                     *buf++ = '.';
  553.                     while( *buf == '0' ) {
  554.                         ++buf;
  555.                     }
  556.                 }
  557.                 *buf++ = '0';
  558.                 *buf = NULLCHAR;
  559.                 break;
  560.             }
  561.             --buf;
  562.             if( *buf == '.' )
  563.                 --buf;
  564.  
  565.             if( *buf != '9' ) {
  566.                 ++ *buf;
  567.                 break;
  568.             }
  569.             *buf = '0';
  570.         }
  571.     }
  572. }
  573.  
  574. static void float_format( CHAR_TYPE *buffer, my_va_list *pargs, SPECS __SLIB *specs )
  575. {
  576. #ifdef __WIDECHAR__
  577.     char                mbBuffer[BUF_SIZE*MB_CUR_MAX];
  578.     _mbcs_SPECS         mbSpecs;
  579.     int                 count;
  580.     size_t              rc;
  581.     char                *p;
  582. #endif // __WIDECHAR__
  583.  
  584. #ifdef __WIDECHAR__
  585.     /*
  586.      * EFG_PRINTF can only handle MBCS buffers and the MBCS version of the
  587.      * SPECS structure.  So, make a _mbcs_SPECS structure equivalent to the
  588.      * _wide_SPECS one, and use that instead.  Note that we can't use
  589.      * memcpy() because some field sizes are different.
  590.      */
  591.     mbSpecs._dest = NULL;               /* this field isn't actually used */
  592.     mbSpecs._flags = specs->_flags;
  593.     mbSpecs._version = specs->_version;
  594.     mbSpecs._fld_width = specs->_fld_width;
  595.     mbSpecs._prec = specs->_prec;
  596.     mbSpecs._output_count = specs->_output_count;
  597.     mbSpecs._n0 = specs->_n0;
  598.     mbSpecs._nz0 = specs->_nz0;
  599.     mbSpecs._n1 = specs->_n1;
  600.     mbSpecs._nz1 = specs->_nz1;
  601.     mbSpecs._n2 = specs->_n2;
  602.     mbSpecs._nz2 = specs->_nz2;
  603.     mbSpecs._character = (char)specs->_character;
  604.     mbSpecs._pad_char = (char)specs->_pad_char;
  605. #endif
  606.  
  607. #ifdef __WIDECHAR__
  608.     EFG_PRINTF( mbBuffer, pargs, &mbSpecs );
  609. #else
  610.     EFG_PRINTF( buffer, pargs, specs );
  611. #endif
  612.  
  613. #ifdef __WIDECHAR__
  614.     /*
  615.      * Now convert the returned information back into our _wide_SPECS
  616.      * structure.  We can't just use mbstowcs because it's an array of
  617.      * characters, not a string.
  618.      */
  619.     p = mbBuffer;
  620.     for( count = 0; count < BUF_SIZE; count++ ) {
  621.         rc = mbtowc( &(buffer[count]), p, MB_CUR_MAX );
  622.         if( rc == -1 ) {
  623.             buffer[count] = L'?';
  624.         }
  625.         p = _mbsinc( p );
  626.     }
  627.     specs->_flags = mbSpecs._flags;
  628.     specs->_version = mbSpecs._version;
  629.     specs->_fld_width = mbSpecs._fld_width;
  630.     specs->_prec = mbSpecs._prec;
  631.     specs->_output_count = mbSpecs._output_count;
  632.     specs->_n0 = mbSpecs._n0;
  633.     specs->_nz0 = mbSpecs._nz0;
  634.     specs->_n1 = mbSpecs._n1;
  635.     specs->_nz1 = mbSpecs._nz1;
  636.     specs->_n2 = mbSpecs._n2;
  637.     specs->_nz2 = mbSpecs._nz2;
  638.     specs->_character = (wchar_t) mbSpecs._character;
  639.     specs->_pad_char = (wchar_t) mbSpecs._pad_char;
  640. #endif
  641. }
  642.  
  643. static void SetZeroPad( SPECS __SLIB *specs )
  644. {
  645.     int         n;
  646.  
  647.     if( !(specs->_flags & SPF_LEFT_ADJUST) ) {
  648.         if( specs->_pad_char == '0' ) {
  649.             n = specs->_fld_width - specs->_n0 - specs->_nz0 -
  650.                     specs->_n1 - specs->_nz1 - specs->_n2 - specs->_nz2;
  651.             if( n > 0 ) {
  652.                 specs->_nz0 += n;
  653.             }
  654.         }
  655.     }
  656. }
  657.  
  658.  
  659. #if !defined( __WIDECHAR__ ) && defined( USE_MBCS_TRANSLATION )
  660. static void write_wide_string( FAR_UNI_STRING str, SPECS *specs,
  661.                                slib_callback_t *out_putc )
  662. {
  663.     int     bytes;
  664.     char    mbBuf[MB_CUR_MAX];
  665.     char    *mbBufPtr;
  666.  
  667.     while( specs->_n1 > 0 ) {
  668.         bytes = wctomb( mbBuf, *str++ );
  669.         if( bytes != -1 ) {
  670.             if( bytes <= specs->_n1 ) {
  671.                 mbBufPtr = mbBuf;
  672.                 while( bytes-- ) {
  673.                     (out_putc)( specs, *mbBufPtr++ );
  674.                     --specs->_n1;
  675.                 }
  676.             } else {
  677.                 specs->_n1 = 0;
  678.             }
  679.         }
  680.     }
  681. }
  682. #endif
  683.  
  684.  
  685. #if defined( __WIDECHAR__ ) && defined( USE_MBCS_TRANSLATION )
  686. static void write_skinny_string( FAR_ASCII_STRING str, SPECS *specs,
  687.                                  slib_callback_t *out_putc )
  688. {
  689.     int                 bytes;
  690.     wchar_t             wc;
  691.     FAR_ASCII_STRING    mbPtr = str;
  692.     char                mbBuf[MB_CUR_MAX];
  693.  
  694.     while( specs->_n1 > 0 ) {
  695.         mbBuf[0] = *mbPtr++;
  696.         if( _ismbblead( mbBuf[0] ) )
  697.             mbBuf[1] = *mbPtr++;
  698.  
  699.         bytes = mbtowc( &wc, mbBuf, MB_CUR_MAX );
  700.         if( bytes <= specs->_n1 ) {
  701.             if( bytes != -1 ) {
  702.                 (out_putc)( specs, wc );
  703.                 specs->_n1 -= bytes;
  704.             }
  705.         } else {
  706.             specs->_n1 = 0;
  707.         }
  708.     }
  709. }
  710. #endif
  711.  
  712.  
  713. static FAR_STRING formstring( CHAR_TYPE *buffer, my_va_list *pargs,
  714.                               SPECS __SLIB *specs, CHAR_TYPE *null_string )
  715. {
  716.     FAR_STRING              arg;
  717.     int                     length;
  718.     int                     radix;
  719. #if defined( __LONG_LONG_SUPPORT__ )
  720.     unsigned long long      long_long_value;
  721. #endif
  722.     unsigned long           long_value;
  723.     unsigned int            int_value;
  724. #if defined( __FAR_SUPPORT__ )
  725.     unsigned int            seg_value;
  726. #endif
  727. #if !defined( __WIDECHAR__ ) && defined( USE_MBCS_TRANSLATION )
  728.     int                     bytes;
  729. #endif
  730.  
  731.     arg = buffer;
  732.  
  733.     specs->_n0 = specs->_nz0 =
  734.     specs->_n1 = specs->_nz1 =
  735.     specs->_n2 = specs->_nz2 = 0;
  736.  
  737.     if( ( specs->_character == 'b' ) ||
  738.         ( specs->_character == 'o' ) ||
  739.         ( specs->_character == 'u' ) ||
  740.         ( specs->_character == 'x' ) ||
  741.         ( specs->_character == 'X' ) ) {
  742. #if defined( __LONG_LONG_SUPPORT__ )
  743.         if( specs->_flags & SPF_LONG_LONG ) {
  744.             long_long_value = va_arg( pargs->v, unsigned long long );
  745.         } else
  746. #endif
  747.         if( specs->_flags & SPF_LONG ) {
  748.             long_value = va_arg( pargs->v, unsigned long );
  749.         } else {
  750.             long_value = va_arg( pargs->v, unsigned );
  751.             if( specs->_flags & SPF_SHORT ) {    /* JBS 92/02/12 */
  752.                 long_value = (unsigned short) long_value;
  753.             } else if( specs->_flags & SPF_CHAR ) {
  754.                 long_value = (unsigned char)long_value;
  755.             }
  756.         }
  757.     } else
  758.  
  759.     if( ( specs->_character == 'd' ) ||
  760.         ( specs->_character == 'i' ) ) {
  761.  
  762. #if defined( __LONG_LONG_SUPPORT__ )
  763.         if( specs->_flags & SPF_LONG_LONG ) {
  764.             long_long_value = va_arg( pargs->v, long long );
  765.         } else
  766. #endif
  767.         if( specs->_flags & SPF_LONG ) {
  768.             long_value = va_arg( pargs->v, long );
  769.         } else {
  770.             long_value = va_arg( pargs->v, int );
  771.             if( specs->_flags & SPF_SHORT ) {    /* JBS 92/02/12 */
  772.                 long_value = (short) long_value;
  773.             } else if( specs->_flags & SPF_CHAR ) {
  774.                 long_value = (signed char)long_value;
  775.             }
  776.         }
  777.         {
  778.             int negative = FALSE;
  779.  
  780. #if defined( __LONG_LONG_SUPPORT__ )
  781.             if( specs->_flags & SPF_LONG_LONG ) {
  782.                 if( (long long)long_long_value < 0 ) {
  783.                     negative = TRUE;
  784.                 }
  785.             } else
  786. #endif
  787.             if( (long)long_value < 0 ) {
  788.                 negative = TRUE;
  789.             }
  790.             if( negative ) {
  791.                 buffer[specs->_n0++] = '-';
  792.  
  793. #if defined( __LONG_LONG_SUPPORT__ )
  794.                 if( specs->_flags & SPF_LONG_LONG ) {
  795.                     long_long_value = -long_long_value;
  796.                 } else
  797. #endif
  798.                 long_value = - long_value;
  799.             } else if( specs->_flags & SPF_FORCE_SIGN ) {
  800.                 buffer[specs->_n0++] = '+';
  801.             } else if( specs->_flags & SPF_BLANK ) {
  802.                 buffer[specs->_n0++] = ' ';
  803.             }
  804.         }
  805.     }
  806.  
  807.     radix  = 10;                        /* base 10 for 'd', 'i' and 'u' */
  808.     switch( specs->_character ) {
  809.     case 'f':
  810.     case 'F':
  811.         if( specs->_flags & SPF_SHORT ) {       /* "%hf"  13-jun-91 */
  812.             long_value = va_arg( pargs->v, long );
  813.             FixedPoint_Format( buffer, long_value, specs );
  814.             specs->_n1 = far_strlen( buffer, -1 );
  815.             break;
  816.         }
  817.         /* types f & F fall through */
  818.  
  819.     case 'g':
  820.     case 'G':
  821.     case 'e':
  822.     case 'E':
  823.         float_format( buffer, pargs, specs );
  824.         SetZeroPad( specs );
  825.         arg++; // = &buffer[1];
  826.         break;
  827.  
  828.     case 's':
  829. #ifndef __NETWARE__
  830.     case WIDE_CHAR_STRING:
  831. #else
  832.     case PASCAL_STRING:
  833. #endif
  834.         // arg has been initialized to point to buffer
  835.         // set buffer[0] to a null character assuming pointer will be NULL
  836.         // If pointer is not null, then arg will be assigned the pointer
  837.         buffer[0] = '\0';                       // assume null pointer
  838. #if defined( __FAR_SUPPORT__ )
  839.         if( specs->_flags & SPF_FAR ) {
  840.             CHAR_TYPE _WCFAR *temp = va_arg( pargs->v, CHAR_TYPE _WCFAR * );
  841.  
  842.             if( temp ) {
  843.                 arg = temp;
  844.             }
  845.         } else if( specs->_flags & SPF_NEAR ) {
  846.             CHAR_TYPE _WCNEAR *temp = va_arg( pargs->v, CHAR_TYPE _WCNEAR * );
  847.  
  848.             if( temp ) {
  849.                 arg = (void *)temp;
  850.             }
  851.         } else {
  852.             CHAR_TYPE *temp = va_arg( pargs->v, CHAR_TYPE * );
  853.  
  854.             if( temp ) {
  855.                 arg = temp;
  856.             }
  857.         }
  858. #else
  859.         {
  860.             CHAR_TYPE *temp = va_arg( pargs->v, CHAR_TYPE * );
  861.  
  862.             if( temp ) {
  863.                 arg = temp;
  864.             }
  865.         }
  866. #endif
  867.  
  868. #ifdef __NETWARE__
  869.         if( specs->_character == PASCAL_STRING ) {
  870. #ifdef __WIDECHAR__
  871.             if( specs->_flags & SPF_SHORT )
  872. #else
  873.             if( specs->_flags & SPF_LONG )
  874. #endif
  875.             {
  876.                 length = *( (_FAR_OTHER_STRING)arg );
  877.                 arg = (FAR_STRING)( (_FAR_OTHER_STRING)arg + 1 );
  878.             } else {
  879.                 length = *arg++;
  880.             }
  881.         } else
  882. #elif !defined( __NETWARE__ ) && !defined( __WIDECHAR__ )
  883.         if( specs->_character == WIDE_CHAR_STRING ) {
  884.             if( specs->_flags & SPF_SHORT ) {
  885.                 length = far_strlen( arg, specs->_prec );
  886.             } else {
  887.                 length = far_other_strlen( arg, specs->_prec );
  888.             }
  889.         } else
  890. #endif
  891.  
  892. #ifdef __WIDECHAR__
  893.         if( specs->_flags & SPF_SHORT ) {
  894. #else
  895.         if( specs->_flags & SPF_LONG ) {
  896. #endif
  897.             length = far_other_strlen( arg, specs->_prec );
  898.         } else {
  899.             length = far_strlen( arg, specs->_prec );
  900.         }
  901.  
  902.         specs->_n1 = length;
  903.         if(( specs->_prec >= 0 ) && ( specs->_prec < length )) {
  904.             specs->_n1 = specs->_prec;
  905.         }
  906.         break;
  907.  
  908.     case 'x':
  909.     case 'X':
  910.         if( specs->_flags & SPF_ALT ) {
  911. #if defined( __LONG_LONG_SUPPORT__ )
  912.             if( specs->_flags & SPF_LONG_LONG ) {
  913.                 if( long_long_value != 0 ) {
  914.                     buffer[specs->_n0++] = '0';
  915.                     buffer[specs->_n0++] = specs->_character;
  916.                 }
  917.             } else
  918. #endif
  919.             if( long_value != 0 ) {
  920.                 buffer[specs->_n0++] = '0';
  921.                 buffer[specs->_n0++] = specs->_character;
  922.             }
  923.         }
  924.         radix = 16;                 /* base 16 */
  925.         goto processNumericTypes;
  926.  
  927.     case 'b':           /* CDH 2003 Apr 23 *//* Add binary mode */
  928.         radix = 2;                  /* base 2 */
  929.         goto processNumericTypes;
  930.  
  931.     case 'o':
  932.         radix = 8;                  /* base 8 */
  933.         /* 'o' conversion falls through */
  934.  
  935.     case 'd':
  936.     case 'i':
  937.     case 'u':
  938. //       'x' and 'X' jumps here
  939.  
  940. processNumericTypes:
  941.         if( specs->_prec != -1 )
  942.             specs->_pad_char = ' ';     /* 30-jul-95, 11-may-99 */
  943.  
  944.         /* radix contains the base; 8 for 'o', 10 for 'd' and 'i' and 'u',
  945.            16 for 'x' and 'X', and 2 for 'b' */
  946.  
  947.         arg = &buffer[ specs->_n0 ];
  948.  
  949. #if defined( __LONG_LONG_SUPPORT__ )
  950.         if( specs->_flags & SPF_LONG_LONG ) {
  951.             if(( specs->_prec == 0 ) && ( long_long_value == 0 )) {
  952.                 *arg = '\0';
  953.                 length = 0;
  954.             } else {
  955.                 __F_NAME(ulltoa,_ulltow)( long_long_value, &buffer[specs->_n0], radix );
  956.                 if( specs->_character == 'X' ) {
  957.                     __F_NAME(strupr,_wcsupr)( buffer );
  958.                 }
  959.                 length = far_strlen( arg, -1 );
  960.             }
  961.         } else
  962. #endif
  963.         if(( specs->_prec == 0 ) && ( long_value == 0 )) {
  964.             *arg = '\0';
  965.             length = 0;
  966.         } else {
  967.             __F_NAME(ultoa,_ultow)( long_value, &buffer[specs->_n0], radix );
  968.             if( specs->_character == 'X' ) {
  969.                 __F_NAME(strupr,_wcsupr)( buffer );
  970.             }
  971.             length = far_strlen( arg, -1 );
  972.         }
  973.         specs->_n1 = length;
  974.         if( specs->_n1 < specs->_prec ) {
  975.             specs->_nz0 = specs->_prec - specs->_n1;
  976.         } else if( specs->_flags & SPF_ALT && radix < 10
  977.          && (!length || (arg[0] != '0')) ) {
  978.             /* For 'b' and 'o' conversions, alternate format forces the number to
  979.              * start with a zero (effectively increases precision by one), but
  980.              * only if it doesn't start with a zero already.
  981.              */
  982.             ++specs->_nz0;
  983.         }
  984.         if( specs->_prec == -1 ) {
  985.             SetZeroPad( specs );
  986.         }
  987.         break;
  988.  
  989.     case 'p':
  990.     case 'P':
  991. #if defined( __FAR_SUPPORT__ )
  992.     #if defined( __BIG_DATA__ )
  993.         if( !( specs->_flags & (SPF_NEAR|SPF_FAR) ) ) {
  994.             specs->_flags |= SPF_FAR;
  995.         }
  996.         if( specs->_fld_width == 0 ) {
  997.             if( specs->_flags & SPF_NEAR ) {
  998.                 specs->_fld_width = sizeof( unsigned ) * 2;
  999.             } else {
  1000.                 specs->_fld_width = sizeof( CHAR_TYPE _WCFAR * ) * 2 + 1;
  1001.             }
  1002.         }
  1003.     #else
  1004.         if( specs->_fld_width == 0 ) {
  1005.             if( specs->_flags & SPF_FAR ) {
  1006.                 specs->_fld_width = sizeof( CHAR_TYPE _WCFAR * ) * 2 + 1;
  1007.             } else {
  1008.                 specs->_fld_width = sizeof( unsigned ) * 2;
  1009.             }
  1010.         }
  1011.     #endif
  1012. #else
  1013.         if( specs->_fld_width == 0 ) {
  1014.             specs->_fld_width = sizeof( unsigned ) * 2;
  1015.         }
  1016. #endif
  1017.         specs->_flags &= ~( SPF_BLANK | SPF_FORCE_SIGN );
  1018.         int_value = va_arg( pargs->v, unsigned );               /* offset */
  1019. #if defined( __FAR_SUPPORT__ )
  1020.         if( specs->_flags & SPF_FAR ) {
  1021.             seg_value = va_arg( pargs->v, unsigned ) & 0xFFFF; /* segment */
  1022.             /* use "unsigned short" for 386 instead of "unsigned" 21-jul-89 */
  1023.             fmt4hex( seg_value, buffer, sizeof( unsigned short ) * 2 );
  1024.             buffer[sizeof(unsigned short)*2] = ':';
  1025.             fmt4hex( int_value, buffer + sizeof( unsigned short ) * 2 + 1,
  1026.                        sizeof( unsigned ) * 2 );
  1027.         } else {
  1028.             fmt4hex( int_value, buffer, sizeof( unsigned ) * 2 );
  1029.         }
  1030. #else
  1031.         fmt4hex( int_value, buffer, sizeof( unsigned ) * 2 );
  1032. #endif
  1033.         if( specs->_character == 'P' ) {
  1034.             __F_NAME(strupr,_wcsupr)( buffer );
  1035.         }
  1036.         specs->_n0 = far_strlen( arg, -1 );
  1037.         break;
  1038.  
  1039.     case 'c':
  1040. #if defined( __WIDECHAR__ ) && defined( USE_MBCS_TRANSLATION )
  1041.         if( specs->_flags & SPF_SHORT ) {
  1042.             char *      mbPtr;
  1043.             char        mbBuf[MB_CUR_MAX];
  1044.             wchar_t     wc;
  1045.  
  1046.             mbPtr = va_arg( pargs->v, char* );
  1047.             mbBuf[0] = mbPtr[0];
  1048.             if( _ismbblead( mbBuf[0] ) )
  1049.                 mbBuf[1] = mbPtr[1];
  1050.  
  1051.             if( mbtowc( &wc, mbBuf, MB_CUR_MAX ) != -1 ) {
  1052.                 buffer[0] = wc;
  1053.             }
  1054.         } else {
  1055.             buffer[0] = va_arg( pargs->v, int );
  1056.         }
  1057.         specs->_n0 = 1;
  1058. #elif !defined( __WIDECHAR__ ) && defined( USE_MBCS_TRANSLATION )
  1059.         specs->_n0 = 1;
  1060.         if( specs->_flags & SPF_LONG ) {
  1061.             char        mbBuf[MB_CUR_MAX];
  1062.             wchar_t     wc;
  1063.  
  1064.             wc = va_arg( pargs->v, int );
  1065.             if( wctomb( mbBuf, wc ) != -1 ) {
  1066.                 buffer[0] = mbBuf[0];
  1067.                 if( _ismbblead( mbBuf[0] ) ) {
  1068.                     buffer[1] = mbBuf[1];
  1069.                     specs->_n0++;
  1070.                 }
  1071.             }
  1072.         } else {
  1073.             buffer[0] = va_arg( pargs->v, int );
  1074.         }
  1075. #else
  1076.         specs->_n0 = 1;
  1077.         buffer[0] = va_arg( pargs->v, int );
  1078. #endif
  1079.         break;
  1080.  
  1081. #if !defined( __WIDECHAR__ ) && defined( USE_MBCS_TRANSLATION )
  1082.     case 'C':
  1083.         bytes = wctomb( buffer, va_arg( pargs->v, int ) );
  1084. //      if( bytes != -1  &&  bytes <= specs->_prec ) {
  1085.         if( bytes != -1 ) { /* Normative Addendum 4.5.3.3.1: no precision */
  1086.             specs->_n0 = bytes;
  1087.         } else {
  1088.             specs->_n0 = 0;
  1089.         }
  1090.         break;
  1091. #endif
  1092.  
  1093.     default:
  1094.         specs->_fld_width = 0;
  1095.         buffer[ 0 ] = specs->_character;
  1096.         specs->_n0 = 1;
  1097.         break;
  1098.     }
  1099.     return( arg );
  1100. }
  1101.