• Welcome to Jose's Read Only Forum 2023.
 

Moving TCLib Into Mainstream

Started by Frederick J. Harris, April 02, 2016, 12:03:13 AM

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

James C. Fuller

Fred,
  I've done a bit of research on File IO but am not up to speed yet on how to implement without FILE or STL, especially a "Line Input" routine.

I already had a bc9 fprint which now works fine.
I do have two functions to read and save a complete ansi text file when app is in Unicode mode.

I did not see any file io comments on the handmade hero link.

James


Frederick J. Harris

Glad you mentioned that about the situation with FILE.  I consider that a downfall of the code I posted regarding fprintf, but the actual situation was that I wanted to implement something quick and dirty which nontheless worked well enough for the debugging purpose I needed at that moment.  Give me a minute and I'll come up with a link to some work a Mike_V did on this.  What he did may work.  I simply never tested it.  Be back in a minute...

Frederick J. Harris

Here's the link...

http://www.codeproject.com/Articles/15156/Tiny-C-Runtime-Library

If you can't get the code for some reason I have it all.  I actually did quite a bit of work early on with Mike_V's code.  That's actually how I got clued in on how to set up wide character support.  Note he doesn't use command line compiling or batch files like we do.  He's using the VS 2005 or VS 2008 IDE.  And his code won't compile as x64 unless you remove one of his floating point math *.cpp files with inline assembler in it (inline asm mostly doesn't work in x64).  Once you remove that his code compiles easily from the command line of in Visual Studio.  I spent some time looking at his file implementations but didnt completely figure it all out.  Its somewhat complex.

Frederick J. Harris

And thanks for pointing that out about my UNICODE defines in Strings.cpp.  That's something I had been doing wrong for so long I never even took notice of it.  Sometimes I don't pay as close attention to proper form as I should.

Frederick J. Harris

And about that _stricmp thing again - not to keep beating a dead horse, but I just looked up the actual inclusions of string compare functions in the C Standard and these are the only ones there...

memcmp     Compare two blocks of memory (function )

strcmp      Compare two strings (function )

strcoll       Compare two strings using locale (function )

strncmp      Compare characters of two strings (function )

strxfrm      Transform string using locale (function )

I've never even used strcoll or strxfrm.


James C. Fuller

Fred,
  I haven't looked at Mike_V's code yet but I did run into a link (lost it) where the author was using
memory mapped files for file io rather than the normal interprocess communication.?

Re _stricmp. It is not a c standard but who cares. The target for me is VS 64bit unicode :)

James


Frederick J. Harris

#21
[QUOTE]
The target for me is VS 64bit unicode


That's mostly true for me too James. 

Wouldn't know anything about a memory mapped file solution to the issue.  But take a look at what Mike_V did with the FILE object.  I think it might be workable (that is, if it works! ;D ).

From my standpoint what I did with the HANDLE instead of FILE objects is temporarily if not long term workable, and fixing it is quite a ways down on my todo list.  But I can see for you in working with your BCX translation code it is far from optimal having two functions with the same name one of which uses FILE* and the other HANDLE.  Maybe you would want to work on fixing it and make a joint project out of this?

For myself, I was next wanting to explore if all this works with ODBC.  I looked over the headers and at least looking at those I didn't see anything in them to suggest the C Runtime was needed.  I'll see.

Then I wanted to explore whether my ActiveX Grid Control could be compiled against TCLib instead of loading C Runtime.  I was never able to get my C++ versions anywhere near as small as My PowerBASIC version.  If I can get it working with TCLib I'm sure I can remedy that.

James C. Fuller

Fred,
  I was thinking more of a file class wrapper as we are using c++. I'll see if I can find that MMF article. It may have been in code project too.

what is
extern "C" int _fltused=1
for?

Sorry if it's in your explanation text. I figured it would be faster to ask than reread. :)

James

Frederick J. Harris

Yes, the extern "C" int _fltused is absolutely of critical importance.  Without that its not even possible to declare a double and assign a floating point number to it.  I'd call that pretty critical. 

Actually, to save you the bother of reading and building Mike_V's work I can test whether his FILE implementation works or not.  I spent days and days working with his code (but never tested that in particular), before abandoning it cuz of what I perceive he screwed up in his sprintf code.  So it would be easy for me to test in a few minutes.

But I may not be able to do it 'till tonight or tomorrow.  Have to find out what I'm doing this afternoon. 

Frederick J. Harris

Turns out my tentative plans to do a little horseback riding this afternoon were cancelled.  The weather here has taken a turn for the worst, to say the least!  I've a crab-apple tree outside my window of my house in full bloom, but right now we've 20 - 40 mph gusting winds and its like 29 degrees F with snow fluries blowing around.

So I just sunk like an hour into seeing if I could get Mike_V's FILE related stdio code working.  No can do.  I keep getting all kinds of bizarre errors, which one gets inured to in doing this 'off the beaten path' type work.  It would really take me several days of work to get to the bottom of it I think, and I'm not inclined right now.  For example though, here are his file.cpp and libct.h files...


// file.cpp

// file routine overrides

// 08/20/05 (mv)
// cl file.cpp /O1 /Os /GL /D "WIN32" /D "NDEBUG" /D "_LIB" /D "_CRT_SECURE_NO_DEPRECATE" /D "_CRT_NONSTDC_NO_DEPRECATE" /FD /MT /GS- /GR- /W4 /c /Zi /TP  /GR-
#include <windows.h>
#include <stdio.h>
#include "libct.h"

/* FILE, as defined in stdio.h
struct _iobuf {
        char *_ptr;
        int   _cnt;
        char *_base; Used to store HANDLE
        int   _flag;
        int   _file;
        int   _charbuf;
        int   _bufsiz;
        char *_tmpfname;
        };
typedef struct _iobuf FILE;
*/

//_flag values (not the ones used by the normal CRT
#define _FILE_TEXT 0x0001
#define _FILE_EOF 0x0002
#define _FILE_ERROR 0x0004

struct _FILE : public FILE
{
void set_handle(HANDLE h) {_base = (char*)h;};
HANDLE get_handle() const {return (HANDLE)_base;};
};

// used directly by the stdin, stdout, and stderr macros
_FILE __iob[3];
FILE *__iob_func() {return (FILE*)__iob;}

void _init_file()
{
// STDIN
__iob[0].set_handle(GetStdHandle(STD_INPUT_HANDLE));
__iob[0]._flag = _FILE_TEXT;

// STDOUT
__iob[1].set_handle(GetStdHandle(STD_OUTPUT_HANDLE));
__iob[1]._flag = _FILE_TEXT;

// STDERR
__iob[2].set_handle(GetStdHandle(STD_ERROR_HANDLE));
__iob[2]._flag = _FILE_TEXT;
}


BEGIN_EXTERN_C

/*int _fileno(FILE *fp)
{
return (int)fp; // FIXME:  This doesn't work under Win64
}

HANDLE _get_osfhandle(int i)
{
return (HANDLE)i; // FIXME:  This doesn't work under Win64
}*/

FILE *fopen(const char *path, const char *attrs)
{
DWORD access, disp;
if (strchr(attrs, 'w'))
{
access = GENERIC_WRITE;
disp = CREATE_ALWAYS;
}
else
{
access = GENERIC_READ;
disp = OPEN_EXISTING;
}

HANDLE hFile = CreateFileA(path, access, 0, 0, disp, 0, 0);
if (hFile == INVALID_HANDLE_VALUE)
return 0;

_FILE *file = new _FILE;
memset(file, 0, sizeof(_FILE));
file->set_handle(hFile);

if (strchr(attrs, 't'))
file->_flag |= _FILE_TEXT;

return file;
}

FILE *_wfopen(const wchar_t *path, const wchar_t *attrs)
{
DWORD access, disp;
if (wcschr(attrs, L'w'))
{
access = GENERIC_WRITE;
disp = CREATE_ALWAYS;
}
else
{
access = GENERIC_READ;
disp = OPEN_EXISTING;
}

HANDLE hFile = CreateFileW(path, access, 0, 0, disp, 0, 0);
if (hFile == INVALID_HANDLE_VALUE)
return 0;

_FILE *file = new _FILE;
memset(file, 0, sizeof(_FILE));
file->set_handle(hFile);

if (wcschr(attrs, L't'))
file->_flag |= _FILE_TEXT;

return file;
}


int fprintf(FILE *fp, const char *s, ...)
{
va_list args;
va_start(args, s);

char bfr[1024];
int len = wvsprintfA(bfr, s, args);
va_end(args);

fwrite(bfr, len+1, sizeof(char), fp);
return len;
}

int fwprintf(FILE *fp, const wchar_t *s, ...)
{
va_list args;
va_start(args, s);

wchar_t bfr[1024];
int len = wvsprintfW(bfr, s, args);

va_end(args);

char ansibfr[1024];
WideCharToMultiByte(CP_ACP, 0, bfr, -1, ansibfr, sizeof(ansibfr), 0, 0);

fwrite(ansibfr, len+1, sizeof(char), fp);
return len;
}


int fclose(FILE *fp)
{
CloseHandle(((_FILE*)fp)->get_handle());
delete fp;
return 0;
}

int feof(FILE *fp)
{
return (fp->_flag & _FILE_EOF) ? 1 : 0;
}

int fseek(FILE *str, long offset, int origin)
{
DWORD meth = FILE_BEGIN;
if (origin == SEEK_CUR)
meth = FILE_CURRENT;
else if (origin == SEEK_END)
meth = FILE_END;
SetFilePointer(((_FILE*)str)->get_handle(), offset, 0, meth);
((_FILE*)str)->_flag &= ~_FILE_EOF;
return 0;
}

long ftell(FILE *fp)
{
return SetFilePointer(((_FILE*)fp)->get_handle(), 0, 0, FILE_CURRENT);
}

size_t fread(void *buffer, size_t size, size_t count, FILE *str)
{
if (size*count == 0)
return 0;
if (feof(str))
return 0;

HANDLE hFile = ((_FILE*)str)->get_handle();
int textMode = ((_FILE*)str)->_flag & _FILE_TEXT;

char *src;
if (textMode)
src = (char*)malloc(size*count);
else
src = (char*)buffer;

DWORD br;
if (!ReadFile(hFile, src, (DWORD)(size*count), &br, 0))
((_FILE*)str)->_flag |= _FILE_ERROR;
else if (!br) // nonzero return value and no bytes read = EOF
((_FILE*)str)->_flag |= _FILE_EOF;

if (!br)
return 0;

// Text-mode translation is always ANSI
if (textMode) // text mode: must translate CR -> LF
{
char *dst = (char*)buffer;
for (DWORD i = 0; i < br; i++)
{
if (src[i] != '\r')
{
*dst++ = src[i];
continue;
}

// If next char is LF -> convert CR to LF
if (i+1 < br)
{
if (src[i+1] == '\n')
{
*dst++ = '\n';
i++;
}
else
*dst++ = src[i];
}
else if (br > 1)
{
// This is the hard part: must peek ahead one byte
DWORD br2 = 0;
char peekChar = 0;
ReadFile(hFile, &peekChar, 1, &br2, 0);
if (!br2)
*dst++ = src[i];
else if (peekChar == '\n')
*dst++ = '\n';
else
{
fseek(str, -1, SEEK_CUR);
*dst++ = src[i];
}
}
else
*dst++ = src[i];
}

free(src);
}

return br/size;
}

size_t fwrite(const void *buffer, size_t size, size_t count, FILE *str)
{
DWORD bw = 0, bw2 = 0;

if (size*count == 0)
return 0;

HANDLE hFile = ((_FILE*)str)->get_handle();
int textMode = ((_FILE*)str)->_flag & _FILE_TEXT;

// Text-mode translation is always ANSI!
if (textMode) // text mode -> translate LF -> CRLF
{
const char *src = (const char*)buffer;
size_t startpos = 0, i = 0;
for (i = 0; i < size*count; i++)
{
if (src[i] != '\n')
continue;
if (i > 0 && src[i-1] == '\r') // don't translate CRLF
continue;

if (i > startpos)
{
WriteFile(hFile, &src[startpos], i-startpos, &bw2, 0);
bw += bw2;
}

const char *crlf = "\r\n";
WriteFile(hFile, crlf, 2, &bw2, 0);
bw++; // one '\n' written

startpos = i+1;
}

if (i > startpos)
{
WriteFile(hFile, &src[startpos], i-startpos, &bw2, 0);
bw += bw2;
}
}
else
WriteFile(hFile, buffer, (DWORD)(size*count), &bw, 0);
return bw/size;
}

char *fgets(char *str, int n, FILE *s)
{
if (feof(s))
return 0;

int i;
for (i = 0; i < n-1; i++)
{
if (!fread(&str[i], 1, sizeof(char), s))
break;
if (str[i] == '\r')
{
i--;
continue;
}
if (str[i] == '\n')
{
i++;
break;
}
}

str[i] = 0;
return str;
}

wchar_t *fgetws(wchar_t *str, int n, FILE *s)
{
// Text-mode fgetws converts MBCS->Unicode
if (((_FILE*)str)->_flag & _FILE_TEXT)
{
char *bfr = (char*)malloc(n);
fgets(bfr, n, s);
MultiByteToWideChar(CP_ACP, 0, bfr, -1, str, n);
free(bfr);
return str;
}

// Binary fgetws reads as Unicode

if (feof(s))
return 0;

int i;
for (i = 0; i < n-1; i++)
{
if (!fread(&str[i], 1, sizeof(wchar_t), s))
break;
if (str[i] == L'\r')
{
i--;
continue; // does i++
}
if (str[i] == L'\n')
{
i++;
break;
}
}

str[i] = 0;
return str;
}


int fgetc(FILE *s)
{
if (s == 0 || feof(s))
return EOF;

char c;
fread(&c, 1, sizeof(char), s);

return (int)c;
}

wint_t fgetwc(FILE *s)
{
if (s == 0 || feof(s))
return (wint_t)EOF;

// text-mode fgetwc reads and converts MBCS
if (((_FILE*)s)->_flag & _FILE_TEXT)
{
char ch = (char)fgetc(s);
wint_t wch;
MultiByteToWideChar(CP_ACP, 0, &ch, 1, (LPWSTR)&wch, 1);
return wch;
}

// binary fgetwc reads unicode

wint_t c;
fread(&c, 1, sizeof(wint_t), s);

return c;
}

END_EXTERN_C



//libct.h

// libct.h

#pragma once

#include <tchar.h>

#ifdef __cplusplus
#define EXTERN_C extern "C"
#define BEGIN_EXTERN_C extern "C" {
#define END_EXTERN_C }
#else
#define EXTERN_C
#define BEGIN_EXTERN_C
#define END_EXTERN_C
#endif



BEGIN_EXTERN_C

extern TCHAR *_argv[];
int _init_args();
void _term_args();

typedef void (__cdecl *_PVFV)();
extern _PVFV __xc_a[], __xc_z[];    /* C++ initializers */

void _initterm(_PVFV *pfbegin, _PVFV *pfend);
void _init_atexit();
void _doexit();

END_EXTERN_C

void _init_file();

 

James C. Fuller

Fred,
  The MMF on code project was MFC.
I did find this one on the PbForum
http://forum.powerbasic.com/forum/user-to-user-discussions/source-code/25065-alternate-line-input
Advantage is the ability to parse HUGE files one line at a time.
Converting to c++ might be a pain.

Re weather: I live 50 miles north of Albany,NY and the sun is a shining but only 32F with a high wind gust of 22.1 mph at 1:12pm
James


Frederick J. Harris

#26
Quote
The MMF on code project was MFC.

What does 'MMF' mean?


Never mind!  "MMF = Memory Mapped File" :-[

Another quick thought.  My fprintf code can be reinterpreted, I believe, to use a FILE* as the first parameter, just like its supposed to be.  Then inside the fprintf it needs to be cast back to a HANDLE.  Also, a cast would be necessary at the point of call to cast the HANDLE returned by CreateFile to a FILE*. 

James C. Fuller

Fred,
  I'm fine with fprintf as it is.

James

James C. Fuller

Fred,
  I was able to convert the Pb code here:
http://forum.powerbasic.com/forum/user-to-user-discussions/source-code/25065-alternate-line-input

but I don't like it as it skips blank lines.

Ballgame Rained/Snowed out so I may get more done today.

James

James C. Fuller

The more I think about it is it so horrible for it to skip blank lines.
I know when I am parsing files using a line input method I need to check for blank lines before I operate on the line.
With this method you know you won't be getting any blank lines.

Fred, 
What do you think?

James