Changeset 41


Ignore:
Timestamp:
Mar 30, 2018, 6:12:15 PM (7 years ago)
Author:
Alex Taylor
Message:

Rewrote Sys2FormatNumber to support LONGLONG and use current locale info from ULS API

Location:
rxutilex/trunk
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • rxutilex/trunk/Makefile

    r39 r41  
    1010LFLAGS = /NOLOGO /MAP
    1111NAME   = rxutilex
    12 LIBS   = rexx.lib
     12LIBS   = rexx.lib libuls.lib libconv.lib
    1313
    1414# Set environment variable DEBUG (=anything) to build with debugging symbols
  • rxutilex/trunk/rxutilex.c

    r40 r41  
    4040
    4141// Uncomment to use legacy C style locale data instead of the OS/2 ULS library
    42 #define LEGACY_C_LOCALE
     42// #define LEGACY_C_LOCALE
    4343
    4444#define INCL_WINATOM
     
    6464#include <string.h>
    6565#include <time.h>
     66#include <locale.h>
    6667
    6768#ifdef LEGACY_C_LOCALE
    68     #include <locale.h>
    6969    #include <nl_types.h>
    7070    #include <langinfo.h>
    7171#else
    7272    #include <unidef.h>
     73    #include <uconv.h>
    7374#endif
    7475
     
    109110#define US_PIDSTR_MAXZ        ( CCHMAXPATH + 100 )                   // ...of a process information string
    110111#define US_TIMESTR_MAXZ         256                                  // ...of a formatted time string
    111 #define US_NUMSTR_MAXZ          64                                   // ...of a formatted number string
     112#define US_NUMSTR_MAXZ          32                                   // ...of a formatted number string
    112113#define US_PIPESTATUS_MAXZ      128                                  // ...of a pipe status string
    113114#define US_DISKINFO_MAXZ        128                                  // ...of a disk information string
     
    197198ULONG GetProcess( PCSZ pszProgram, PSZ pszFullName, PULONG pulPID, PULONG pulPPID, PULONG pulType, PUSHORT pusPriority, PULONG pulCPU );        // 2016-02-20 SHL
    198199
     200#ifndef LEGACY_C_LOCALE
     201int GetLocaleString( PSZ *ppszItem, LocaleItem item );
     202    void GroupNumber( PSZ buf, ULONGLONG val, PSZ sep );
     203#endif
     204
    199205#ifdef NO_SHARED_SOURCE
    200206    BOOL  SaveResultString( PRXSTRING prsResult, PCSZ pchBytes, ULONG ulBytes );    // 2016-02-20 SHL
     
    10721078{
    10731079    CHAR  achNumber[ US_NUMSTR_MAXZ ];  // Formatted output string
    1074     float fVal;                         // Input value as floating point
     1080    int   iPrec;                        // Requested decimal precision
     1081    PSZ   pszSep = NULL;                // Thousands separator string
     1082    PSZ   pszDec = NULL;                // Decimal point string
     1083#ifdef LEGACY_C_LOCALE
     1084    float fVal = 0;                     // Input value as floating point
    10751085    int   iVal;                         // Input value as integer
    1076     int   iPrec;                        // Requested decimal precision
    1077     PSZ   pszSep = NULL;                // Separator string
    1078 #ifndef LEGACY_C_LOCALE
    1079     CHAR  achTemp[ US_NUMSTR_MAXZ ];    // Temporary buffer
    1080     LocaleObject     locale = NULL;     // ULS locale object
    1081     struct UniLconv *punilc = NULL;     // ULS locale conventions structure
    1082     CHAR            *p      = NULL;     // Moving pointers within buffers
    1083     CHAR            *q      = NULL;     // ...
    1084     int              rc     = 0;
     1086#else
     1087    ULONGLONG   llVal  = 0;
     1088    long double ldVal  = 0,
     1089                ldFrac = 0;
     1090    PSZ   p;
     1091    CHAR  achFrac[ 16 ];
     1092    int   rc     = 0;
    10851093#endif
    10861094
     
    11091117            else if ( !strnicmp( p, "it", 2 )) setlocale( LC_NUMERIC, "IT_IT");
    11101118            else if ( !strnicmp( p, "ja", 2 )) setlocale( LC_NUMERIC, "JA_JP");
    1111 /*
     1119/* -- it seems the VAC runtime doesn't recognize most of these...
    11121120            else if ( !strnicmp( p, "ar", 2 )) setlocale( LC_NUMERIC, "ar_AA");
    11131121            else if ( !strnicmp( p, "be", 2 )) setlocale( LC_NUMERIC, "be_BY");
     
    11451153            else if ( !strnicmp( p, "uk", 2 )) setlocale( LC_NUMERIC, "uk_UA");
    11461154            else if ( !strnicmp( p, "zh", 2 )) setlocale( LC_NUMERIC, "zh_TW");
    1147 */
     1155-- */
    11481156            else setlocale( LC_NUMERIC, "EN_US");
    11491157            free(p);
     
    11711179
    11721180#else
    1173     rc = UniCreateLocaleObject( UNI_MBS_STRING_POINTER, "", &locale );
    1174     if ( rc != ULS_SUCCESS ) {
    1175         WriteErrorCode( rc, "UniCreateLocaleObject");
    1176         SaveResultString( prsResult, NULL, 0 ); // 2016-02-20 SHL
     1181
     1182    rc = GetLocaleString( &pszSep, LOCI_sThousand );
     1183    if ( rc ) {
     1184        // GetLocaleString has already set the error indicator
     1185        SaveResultString( prsResult, NULL, 0 );
    11771186        return ( 0 );
    11781187    }
    1179     rc = UniQueryLocaleInfo(locale_object, &puni_lconv);
    1180     if ( rc != ULS_SUCCESS ) {
    1181         WriteErrorCode( rc, "UniQueryLocaleInfo");
    1182         SaveResultString( prsResult, NULL, 0 ); // 2016-02-20 SHL
     1188    rc = GetLocaleString( &pszDec, LOCI_sDecimal );
     1189    if ( rc ) {
     1190        // GetLocaleString has already set the error indicator
     1191        SaveResultString( prsResult, NULL, 0 );
    11831192        return ( 0 );
    1184      }
     1193    }
    11851194
    11861195    // Check for a decimal place and treat as float or integer accordingly
    11871196    if ( strchr( argv[0].strptr, '.') != NULL ) {
    1188         if (( sscanf( argv[0].strptr, "%f", &fVal )) != 1 ) return ( 40 );
     1197        if (( sscanf( argv[0].strptr, "%Lf", &ldVal )) != 1 ) return ( 40 );
     1198
     1199        llVal  = ldVal;
     1200        ldFrac = ldVal - llVal;
    11891201        if ( argc >= 2  && ( RXVALIDSTRING(argv[1]) ) &&
    11901202             (( sscanf( argv[1].strptr, "%d", &iPrec )) == 1 ))
    11911203        {
    11921204            // Use user-specified precision
    1193             sprintf( achNumber, "%.*f", iPrec, fVal );
     1205            sprintf( achFrac, "%.*Lf", iPrec, ldFrac );
    11941206        }
    11951207        else
    1196             sprintf( achNumber, "%.2f", fVal );
     1208            sprintf( achFrac, "%.2Lf", ldFrac );
     1209        // Format the integer part
     1210        GroupNumber( achNumber, llVal, pszSep );
     1211        // Append the fractional part
     1212        if (( p = strchr( achFrac, '.')) != NULL ) {
     1213            strncat( achNumber, pszDec, US_NUMSTR_MAXZ - 1 );
     1214            strncat( achNumber, p+1,    US_NUMSTR_MAXZ - 1 );
     1215        }
    11971216    }
    11981217    else {
    1199         if (( sscanf( argv[0].strptr, "%d", &iVal )) != 1 ) return ( 40 );
    1200         sprintf( achNumber, "%d", iVal );
    1201     }
    1202 
     1218        if (( sscanf( argv[0].strptr, "%lld", &llVal )) != 1 ) return ( 40 );
     1219        GroupNumber( achNumber, llVal, pszSep );
     1220    }
     1221
     1222    free( pszSep );
    12031223#endif
    12041224
     
    28622882
    28632883
     2884#ifndef LEGACY_C_LOCALE
     2885
     2886/* ------------------------------------------------------------------------- *
     2887 * GetLocaleString                                                           *
     2888 *                                                                           *
     2889 * Get the requested representation string for the current locale.           *
     2890 * The argument is a pointer to a string which will be allocated by this     *
     2891 * function.  It is the caller's responsibility to free() it.                *
     2892 *                                                                           *
     2893 * ARGUMENTS:                                                                *
     2894 *   PSZ   *ppszItem: Pointer to string to be allocated.                 (O) *
     2895 *   LocaleItem item: Locale item to query.                              (I) *
     2896 *                                                                           *
     2897 * RETURNS: int                                                              *
     2898 *   The ULS function return code.                                           *
     2899 * ------------------------------------------------------------------------- */
     2900int GetLocaleString( PSZ *ppszItem, LocaleItem item )
     2901{
     2902    UconvObject  uconv = NULL;
     2903    LocaleObject locale = NULL;
     2904    UniChar     *puzSep;
     2905    int          rc = 0;
     2906    int          buf_size;
     2907    PSZ          pszBuffer;
     2908
     2909    rc = UniCreateLocaleObject( UNI_MBS_STRING_POINTER, "", &locale );
     2910    if ( rc != ULS_SUCCESS ) {
     2911        WriteErrorCode( rc, "UniCreateLocaleObject");
     2912        return ( rc );
     2913    }
     2914    rc = UniQueryLocaleItem( locale, item, &puzSep );
     2915    if ( rc == ULS_SUCCESS ) {
     2916        buf_size = UniStrlen( puzSep ) * 3;
     2917        pszBuffer = (PSZ) calloc( 1, buf_size + 1 );
     2918        if ( pszBuffer ) {
     2919            if ( UniCreateUconvObject(L"", &uconv ) == ULS_SUCCESS ) {
     2920                if ( UniStrFromUcs( uconv, pszBuffer, puzSep, buf_size ))
     2921                    sprintf( pszBuffer, "%ls", puzSep );
     2922                UniFreeUconvObject( uconv );
     2923            }
     2924            else
     2925                sprintf( pszBuffer, "%ls", puzSep );
     2926            *ppszItem = pszBuffer;
     2927        }
     2928        else {
     2929            rc = ERROR_NOT_ENOUGH_MEMORY;
     2930            WriteErrorCode( rc, "calloc");
     2931        }
     2932        UniFreeMem( puzSep );
     2933    }
     2934    else WriteErrorCode( rc, "UniQueryLocaleItem");
     2935
     2936    UniFreeLocaleObject( locale );
     2937    return ( rc );
     2938}
     2939
     2940
     2941/* ------------------------------------------------------------------------- *
     2942 * GroupNumber                                                               *
     2943 *                                                                           *
     2944 * Format an unsigned number into three-digit (thousands) groups, separated  *
     2945 * by the designated separator string. The output buffer must be allocated,  *
     2946 * and must be large enough to hold a 64-bit integer with the added          *
     2947 * separators, i.e. 20 + (separator length * 6 ).  This function does not    *
     2948 * perform any bounds checking, so the caller must ensure this.              *
     2949 *                                                                           *
     2950 * ARGUMENTS:                                                                *
     2951 *   PSZ       buf: The output string buffer.                           (IO) *
     2952 *   ULONGLONG val: The number value to format.                          (I) *
     2953 *   PSZ       sep: The group-separator string.                          (I) *
     2954 *                                                                           *
     2955 * RETURNS: N/A                                                              *
     2956 * ------------------------------------------------------------------------- */
     2957void GroupNumber( PSZ buf, ULONGLONG val, PSZ sep )
     2958{
     2959    if ( val < 1000 ) {
     2960        sprintf( buf, "%u", val );
     2961        return;
     2962    }
     2963    GroupNumber( buf, val / 1000, sep );
     2964    sprintf( buf+strlen(buf), "%s%03u", sep, val % 1000 );
     2965}
     2966
     2967#endif      // #ifndef LEGACY_C_LOCALE
    28642968
    28652969
     
    29973101}
    29983102
    2999 #endif // NO_SHARED_SOURCE
    3000 
     3103#endif      // #ifdef NO_SHARED_SOURCE
     3104
  • rxutilex/trunk/rxutilex.def

    r40 r41  
    11LIBRARY     RXUTILEX INITINSTANCE TERMINSTANCE
    22DATA        MULTIPLE NONSHARED
    3 DESCRIPTION '@#Alex Taylor:0.1.6#@##1## 29 Mar 2018 23:50:30     REINFORCE::::::@@Extended REXX Utility Functions'
     3DESCRIPTION '@#Alex Taylor:0.1.6#@##1## 30 Mar 2018 12:07:43     REINFORCE::::::@@Extended REXX Utility Functions'
    44
    55EXPORTS     Sys2LoadFuncs
  • rxutilex/trunk/testlib.cmd

    r40 r41  
    5050
    5151say 'Current screen resolution:' Sys2QuerySysValue('CXSCREEN') Sys2QuerySysValue('CYSCREEN')
     52say
     53
     54say Sys2FormatNumber('9375739912303')
     55say Sys2FormatNumber('64583.449286', 5)
     56
    5257
    5358call Sys2DropFuncs
Note: See TracChangeset for help on using the changeset viewer.