IT-Consultant: Frederick J. Harris > Discussion

Moving TCLib Into Mainstream

<< < (17/17)

Frederick J. Harris:
Sorry I took so long in posting this.  Its the original I got working, and was thinking I could improve on it by simply recopying the string representation of a number to another buffer without the decimal point, calling atoi on that, then dividing the result in a loop by ten till I got the right value.  Might save a couple lines from what I have now.  But here is what I have now...


--- Code: ---//==============================================================================================
//               Developed As An Addition To Matt Pietrek's LibCTiny.lib
//                             By Fred Harris, May 2016
//
//        cl atof.cpp /D "_CRT_SECURE_NO_WARNINGS" /c /W3 /DWIN32_LEAN_AND_MEAN
//==============================================================================================
#include <windows.h>
#include "stdlib.h"
typedef SSIZE_T ssize_t;

double __cdecl atof(const char* pStr)
{
 ssize_t lTotal   = 0;
 char* pDecPt     = NULL;
 char c,cNeg      = NULL;
 double dblReturn;
 size_t iDiff;

 while(*pStr==32 || *pStr==8 || *pStr==48)
    pStr++;
 if(*pStr=='-')
 {
    cNeg='-';
    pStr++;
 }
 while(*pStr)
 {
    if(*pStr=='.')
    {
       pDecPt=(char*)pStr;
       pStr++;
    }
    else
    {
       c=*pStr++;
       lTotal=10*lTotal+(c-48); // Add this digit to the total.
    }
 }
 if(pDecPt)
    iDiff=(int)(pStr-pDecPt-1);
 else
    iDiff=0;
 if(cNeg=='-')                  // If we have a negative sign, convert the value.
    lTotal=-lTotal;
 dblReturn=(double)lTotal;
 for(size_t i=0; i<iDiff; i++)
     dblReturn=dblReturn/10;

 return dblReturn;
}

double __cdecl _wtof(const wchar_t* pStr)
{
 ssize_t lTotal = 0;
 wchar_t* pDecPt=NULL;
 wchar_t c,cNeg=NULL;
 double dblReturn;
 size_t iDiff;

 while(*pStr==32 || *pStr==8 || *pStr==48)
    pStr++;
 if(*pStr==L'-')
 {
    cNeg=L'-';
    pStr++;
 }
 while(*pStr)
 {
    if(*pStr==L'.')
    {
       pDecPt=(wchar_t*)pStr;
       pStr++;
    }
    else
    {
       c=*pStr++;
       lTotal=10*lTotal+(c-48); // Add this digit to the total.
    }
 }
 if(pDecPt)
    iDiff=(int)(pStr-pDecPt-1);
 else
    iDiff=0;
 if(cNeg==L'-')                  // If we have a negative sign, convert the value.
    lTotal=-lTotal;
 dblReturn=(double)lTotal;
 for(size_t i=0; i<iDiff; i++)
     dblReturn=dblReturn/10;

 return dblReturn;
}

--- End code ---

Those functions need to be added to stdlib.h too...


--- Code: ---// stdlib.h
#ifndef stdlib_h
#define stdlib_h
   #define NULL 0
   extern "C" void*   __cdecl malloc  (size_t          size);
   extern "C" void    __cdecl free    (void*           pMem);
   extern "C" long    __cdecl atol    (const char*     pStr);
   extern "C" int     __cdecl atoi    (const char*     pStr);
   extern "C" long    __cdecl _wtol   (const wchar_t*  pStr);
   extern "C" _int64  __cdecl _atoi64 (const char*     pStr);
   extern "C" _int64  __cdecl _wtoi64 (const wchar_t*  pStr);
   extern "C" double  __cdecl atof    (const char*     pStr);
   extern "C" double  __cdecl _wtof   (const wchar_t*  pStr);
   extern "C" int     __cdecl abs     (int             n   );
   extern "C" long    __cdecl labs    (long            n   );
   extern "C" _int64  __cdecl _abs64  (__int64         n   );
#endif

--- End code ---

And maybe to tchar.h if you use those....


--- Code: ---// tchar.h
#ifndef tchar_h
   #define tchar_h
   #ifdef  _UNICODE
      typedef wchar_t     TCHAR;
      #define _T(x)       L## x
      #define _tmain      wmain
      #define _tWinMain   wWinMain
      #define _tfopen     _wfopen
      #define _fgetts     fgetws
      #define _tprintf    wprintf
      #define _ftprintf   fwprintf
      #define _stprintf   swprintf
      #define _tcslen     wcslen
      #define _tcscpy     wcscpy
      #define _tcscat     wcscat
      #define _tcsncpy    wcsncpy
      #define _tcscmp     wcscmp
      #define _tcsicmp    _wcsicmp
      #define _tcsncmp    wcsncmp
      #define _tcsnicmp   _wcsnicmp
      #define _tcsrev     _wcsrev
      #define FltToTch    FltToWch
      #define _ttol       _wtol
      #define _ttoi64     _wtoi64
      #define _ttof       _wtof
   #else
      typedef char        TCHAR;
      #define _T(x)       x
      #define _tmain      main
      #define _tWinMain   WinMain
      #define _tfopen     fopen
      #define _fgetts     fgets
      #define _tprintf    printf
      #define _ftprintf   fprintf
      #define _stprintf   sprintf
      #define _tcslen     strlen
      #define _tcscpy     strcpy
      #define _tcscat     strcat
      #define _tcsncpy    strncpy
      #define _tcscmp     strcmp
      #define _tcsicmp    _stricmp
      #define _tcsncmp    strncmp
      #define _tcsnicmp   _strnicmp
      #define _tcsrev     _strrev
      #define FltToTch    FltToCh
      #define _ttol       atol
      #define _ttoi64     _atoi64
      #define _ttof       atof
   #endif
#endif

--- End code ---

And in terms of my floating point delema with sprint, printf, and fprintf, I'm just having to leave it alone the way I have it where %f doesn't work, and one must either use my string class String::Format() or FltToTch().

Frederick J. Harris:
Had it all along.  Just forgot how I named it (Demo of atof())...


--- Code: ---// cl Demo27.cpp /O1 /Os /GS- /link TCLib.lib kernel32.lib
// 5,120 bytes VC15
// 6,144 bytes VC19
#define UNICODE
#define _UNICODE
#include <windows.h>
#include "stdio.h"
#include "stdlib.h"
#include "tchar.h"
extern "C" int _fltused=1.0;

int main()
{
 TCHAR* pStrs[]={_T("  -12345.678987654"), _T("0.99"), _T("0"), _T("1"), _T("-0.009")};
 TCHAR szConvertedDouble[24];
 double dblNumber;
 
 for(size_t i=0; i<sizeof(pStrs)/sizeof(pStrs[0]); i++)
 {
     dblNumber=_ttof(pStrs[i]);
     FltToTch(szConvertedDouble,dblNumber,24,9,_T('.'),true);
     _tprintf(_T("szConvertedDouble=%s\n"),szConvertedDouble);
 }
 getchar();

 return 0;
}
// Output:
// ==================
// C:\Code\VStudio\VC15\LibCTiny\x64\Test20>Demo27
// szConvertedDouble=       -12345.678987654
// szConvertedDouble=            0.990000000
// szConvertedDouble=            0.000000000
// szConvertedDouble=            1.000000000
// szConvertedDouble=           -0.009000000

--- End code ---

And this is what my TCLib.mak file now looks like.  You don't need those last two if you aren't interested in x86...


--- Code: ---PROJ       = TCLib

OBJS       = crt_con_a.obj crt_con_w.obj crt_win_a.obj crt_win_w.obj memset.obj newdel.obj printf.obj \
             sprintf.obj _strnicmp.obj strncpy.obj strncmp.obj _strrev.obj strcat.obj strcmp.obj \
             strcpy.obj strlen.obj getchar.obj alloc.obj alloc2.obj allocsup.obj FltToCh.obj atol.obj \
             _atoi64.obj abs.obj memcpy.obj strchr.obj fopen.obj fprintf.obj _stricmp.obj fgets.obj \
             atof.obj win32_crt_math.obj win32_crt_Float.obj
       
CC         = CL
CC_OPTIONS = /D "_CRT_SECURE_NO_WARNINGS" /O1 /Os /GS- /c /W3 /DWIN32_LEAN_AND_MEAN

$(PROJ).LIB: $(OBJS)
    LIB /NODEFAULTLIB /machine:x64 /OUT:$(PROJ).lib $(OBJS)

.CPP.OBJ:
    $(CC) $(CC_OPTIONS) $<

--- End code ---

Frederick J. Harris:
Back to the issue of files and unicode again. 

As I suspected (just tested it out now to make absolutely sure), when one uses fwprintf() and there is a wide character parameter, the C Runtime writes the data to the file as asci!  Here's a program to prove it...


--- Code: ---// cl Test1.cpp /O1 /Os /MT
// 125,952 ansi
// 128,512 wide
#define UNICODE
#define _UNICODE
#include <stdio.h>
#include <tchar.h>

int main()
{
 FILE* fp=NULL;
 
 fp=_tfopen(_T("Data.txt"),_T("w"));
 if(fp)
 {
    _ftprintf(fp,_T("Hello, World!\n"));
    _tprintf(_T("Hello, World!\n"));
    fclose(fp);
    getchar();
 }
 
 return 0;
}

--- End code ---

Note the above program isn't using my TCLib.lib, but is rather linking in the typical manner with the C Runtime.  And it opens "Data.txt" and writes "Hello, World!" to the file.  If you check out the count of bytes in the file using Windows Explorer >> File Properties you'll see it is 15 bytes - 13 bytes for "Hello, World!" and two bytes for the CrLf.  This in spite of the fact that all wide character versions of the file opening and writing functions were used.  If the file had been written as UNICODE it should have been 30 bytes. 

And so I have something of a disjuncture with my TCLib and the C Runtime on this issue.  That same program above using my TCLib would have output the string with two bytes per character for a total file size of 30 bytes (I've tested it).  And if you open the file in Notepad and use Save As... it'll show up as a UNICODE file.

So what to do?

I just changed my fwprintf routine to work the way the C Runtime does.  I don't see much else I can do.  I want my TCLib to be as compatible with the C Runtime as possible.  So here is that file now...


--- Code: ---//=============================================================
//   Developed As An Addition To Matt Pietrek's LibCTiny.lib
//                By Fred Harris, March 2016
//
//  cl fprintf.cpp /O1 /Os /GS- /c /W3 /DWIN32_LEAN_AND_MEAN   
//=============================================================
// cl sprintf.cpp /O1 /Os /GS- /c /W3 /DWIN32_LEAN_AND_MEAN
#include <windows.h>
#include <stdarg.h>
#include "stdio.h"
#define EOF (-1)
#pragma comment(linker, "/defaultlib:user32.lib")

int __cdecl fprintf(FILE* fp, const char* format, ...)
{
 char szBuff[1024];
 DWORD cbWritten;
 va_list argptr;
 int retValue;

 va_start(argptr, format);
 retValue = wvsprintfA(szBuff, format, argptr);
 va_end(argptr);
 WriteFile((HANDLE)fp, szBuff, retValue, &cbWritten, 0);

 return retValue;
}

int __cdecl fwprintf(FILE* fp, const wchar_t* pszFormat, ...)  // incomming pointers to character strings will be pointing to wide character strings
{                                                             
 wchar_t szBuff[512];                                          // wide character strings will be written to here
 char szAsci[512];                                             // this variable/buffer will contain converted string (from wide to narrow)
 DWORD cbWritten;
 va_list argptr;
 int retValue;

 va_start(argptr, pszFormat);
 retValue = wvsprintfW(szBuff, pszFormat, argptr);
 va_end(argptr);
 WideCharToMultiByte(CP_ACP,0,szBuff,(int)wcslen(szBuff),szAsci,512,NULL,NULL);  // convert wide szBuff to narrow szAsci
 WriteFile((HANDLE)fp, szAsci, retValue, &cbWritten, 0);                         // output retValue # of bytes

 return retValue;
}

--- End code ---

Another change too.  Not related to files though.  Its an improvement on my atol().  It really needs to test each character during the conversion to make sure the character is a digit, i.e., code between 48 and 57...


--- Code: ---//==============================================================================================
//               Developed As An Addition To Matt Pietrek's LibCTiny.lib
//                             By Fred Harris, March 2016
//
//        cl atol.cpp /D "_CRT_SECURE_NO_WARNINGS" /c /W3 /DWIN32_LEAN_AND_MEAN
//==============================================================================================
#include "stdlib.h"

long __cdecl atol(const char* pStr)
{
 char c,cNeg=NULL;           // c holds the char; cNeg holds the '-' sign.
 long lTotal=0;              // The running total.

 while(*pStr==32 || *pStr==8)
    pStr++; 
 if(*pStr=='-')
 {
    cNeg='-';
    pStr++;
 }
 while(*pStr)
 {
    if(*pStr>=48 && *pStr<=57)
    {
       c=*pStr++;
       lTotal=10*lTotal+(c-48); // Add this digit to the total.
    }
    else
       pStr++;     
 }
 if(cNeg=='-')               // If we have a negative sign, convert the value.
    lTotal=-lTotal;
 
 return lTotal;
}

int __cdecl atoi (const char* pStr)
{
 return ((int)atol(pStr));
}

long __cdecl _wtol(const wchar_t* pStr)
{
 wchar_t c,cNeg=NULL;        // c holds the char; cNeg holds the '-' sign.
 long lTotal=0;              // The running total.

 while(*pStr==32 || *pStr==8)
    pStr++; 
 if(*pStr==L'-')
 {
    cNeg=L'-';
    pStr++;
 }
 while(*pStr)
 {
    if(*pStr>=48 && *pStr<=57)
    {
       c=*pStr++;
       lTotal=10*lTotal+(c-48); // Add this digit to the total.
    }
    else
       pStr++;     
 }
 if(cNeg==L'-')              // If we have a negative sign, convert the value.
    lTotal=-lTotal;
 
 return lTotal;
}


int __cdecl _wtoi (const wchar_t* pStr)
{
 return ((int)_wtol(pStr));
}

--- End code ---


All this nastiness is coming out now that I'm actually using this on a major production app.

Navigation

[0] Message Index

[*] Previous page

Go to full version