IT-Consultant: Frederick J. Harris > Discussion
Moving TCLib Into Mainstream
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