Checking if a string is empty? Topic is solved

If you are using the main C++ distribution of wxWidgets, Feel free to ask any question related to wxWidgets development here. This means questions regarding to C++ and wxWidgets, not compile problems.
Post Reply
Nathan
Experienced Solver
Experienced Solver
Posts: 83
Joined: Sat May 13, 2006 2:22 pm
Location: United States
Contact:

Checking if a string is empty?

Post by Nathan » Tue Jan 06, 2009 11:14 pm

I'm receiving CHARs over the serial port and am running into a little problem.

If I just send ascii characters, everything's fine. But if I send a character with a number out of ascii range my code for checking if the string is empty doesn't work:

Code: Select all

		if(!wxString(szBuff,wxConvUTF8).IsEmpty()) // Don't create event unless there's new data, now wouldn't that be wasteful?
		{
			
			wxCommandEvent event( wxEVT_SERIAL, ID_SERIAL );
			event.SetString( wxString(szBuff,wxConvUTF8) );
			wxPostEvent( m_frame, event ); // m_frame is the pointer to the parent class 
		}
		else
		{
			wxMessageBox(wxT("Empty"));
		}
Is that because the .IsEmpty() function only checks for valid ascii characters? Is there a way to check if there are decimal or hex values as well? I think that's the issue here.

Help! :shock:

radcapricorn
Experienced Solver
Experienced Solver
Posts: 70
Joined: Fri Nov 07, 2008 4:25 pm
Location: Saint-Petersburg, Russia

Post by radcapricorn » Tue Jan 06, 2009 11:44 pm

Well, here's the interesting counter-question. How can ASCII character code be outside of ASCII table range?

What's the type of szBuff, what's the type of CHAR?..

And, lastly, well, if I totally don't understand the question... Are you sure that your szBuff ends with terminator? I'm asking because you either should know (and pass as a constructor parameter) the length of the source string or just be sure it's properly terminated.
win xp pro sp3/VS Express 2008/MinGW;
win Vista Ultimate/VS 2005;
Debian Lenny/gcc/cegcc-mingw32ce;
wxWidgets-2.8.9 w/wxWinCE;

Nathan
Experienced Solver
Experienced Solver
Posts: 83
Joined: Sat May 13, 2006 2:22 pm
Location: United States
Contact:

Post by Nathan » Wed Jan 07, 2009 12:31 am

radcapricorn wrote:Well, here's the interesting counter-question. How can ASCII character code be outside of ASCII table range?
The bytes I'm sending are not actually ascii character codes, but ARE CHARs. So when wxWidgets gets a hold of them, since the data is a CHAR, it treats it like an ascii character.

I've viewed the character stream in a serial terminal program, so I know the data is coming through, but with the code I posted above the "wxMessageBox(wxT("Empty"));" code gets run which means the "if(!wxString(szBuff,wxConvUTF8).IsEmpty())" line is NOT doing what I intended (because the data actually IS there).

radcapricorn wrote:What's the type of szBuff, what's the type of CHAR?..
"szBuff" is a char array. The type of char? I assume it's unsigned since I didn't explicitly make it signed. You can look in the code below, though.
radcapricorn wrote:And, lastly, well, if I totally don't understand the question... Are you sure that your szBuff ends with terminator? I'm asking because you either should know (and pass as a constructor parameter) the length of the source string or just be sure it's properly terminated.
I don't know. I'm not really sure how string/char terminators work. Maybe looking at the entire function below would answer that?

Code: Select all

void *MyThread::Entry()
{
	const int numBytes = 1; // Set number of bytes to read
	while(1)
	{
		char szBuff[numBytes + 1] = {0}; // RESET BUFFER EACH LOOP, otherwise, if no new data, same buffer will be sent with event
		DWORD dwBytesRead = 0;			 // The number of bytes ACTUALLY read get stored here
		if(!ReadFile(hSerial, szBuff, numBytes, &dwBytesRead, NULL))
		{
			wxMessageBox(wxT("Error Reading File (COM Port)\nError: L104")); //error occurred. Report to user.
			wxMessageBox(wxT("Stopping the thread.. You will need to restart the COM port to continue debugging"));
			Exit();
		}

		if(!wxString(szBuff,wxConvUTF8).IsEmpty()) // Don't create event unless there's new data, now wouldn't that be wasteful?
		{
			
			wxCommandEvent event( wxEVT_SERIAL, ID_SERIAL );
			event.SetString( wxString(szBuff,wxConvUTF8) );
			wxPostEvent( m_frame, event ); // m_frame is the pointer to the parent class 
		}
		else
		{
			wxMessageBox(wxT("Empty"));
		}
	}
    return NULL;
}
Thanks for the help!!!

User avatar
doublemax
Moderator
Moderator
Posts: 14086
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Post by doublemax » Wed Jan 07, 2009 12:48 am

Code: Select all

wxString(szBuff,wxConvUTF8)
this will fail (=return an empty string) if szBuff does not contain a valid utf-8 sequence. This is probably what happens in your case.

But you already know how many bytes you received, so why the check?

Anyway, you have to know exactly what kind of data you're receiving. If it's arbitrary binary data, wxString is not a good container for it. If it's string data you need to know how it's encoded and use the proper decoding.
Use the source, Luke!

timg
Earned some good credits
Earned some good credits
Posts: 148
Joined: Mon Jan 23, 2006 6:52 pm

Post by timg » Wed Jan 07, 2009 12:48 am

Silly question, but since you are getting the number of bytes read (dwBytesRead), why wouldn't you just check to see if dwBytesRead > 0?

Nathan
Experienced Solver
Experienced Solver
Posts: 83
Joined: Sat May 13, 2006 2:22 pm
Location: United States
Contact:

Post by Nathan » Wed Jan 07, 2009 12:59 am

Right now the code is failing when the number "F4", or 244, comes through.

I know how many bytes I WANT to read from the "file" (serial port), but I have no way of telling if data was actually gotten (I'm pretty sure empty chars can be read). Hence why I need a way of checking.

The data is actually just integer numbers stored in CHARs.

I'm using String as the container because I don't know of another way to pass data through an event. Right now I'm using "event.SetString", is there another, better way?

Nathan
Experienced Solver
Experienced Solver
Posts: 83
Joined: Sat May 13, 2006 2:22 pm
Location: United States
Contact:

Post by Nathan » Wed Jan 07, 2009 1:04 am

I guess I can probably just check if the CHAR array is null, since I initialize it to zero, but I still don't know how to pass it through the event. Would "event.SetInt()" work? Or would that mess up the data since it's a CHAR?

User avatar
doublemax
Moderator
Moderator
Posts: 14086
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Post by doublemax » Wed Jan 07, 2009 1:20 am

with event.SetInt() you could only send one char (or 4 if you squeeze them into the integer value), but this is probably not what you want here.

Best solution would be to process the bytes right in the thread instead of sending them to the main thread.

If that is not an option, i personally would use a fifo buffer (stl queue or something you build yourself), and protect it with a mutex to exchange data with the main thread. Then i would just send an event that new data has arrived (but not the data itself)

As a quick hack, you could try forcing the data into a wxString by using any 8bit encoding (wxConvISO8859_1), but then you have to decode them again in the main thread instead of using the characters of the string directly (they could be different from the ones you put in). (I'm not 100% sure this works, just an idea)
Last edited by doublemax on Wed Jan 07, 2009 1:21 am, edited 1 time in total.
Use the source, Luke!

radcapricorn
Experienced Solver
Experienced Solver
Posts: 70
Joined: Fri Nov 07, 2008 4:25 pm
Location: Saint-Petersburg, Russia

Post by radcapricorn » Wed Jan 07, 2009 1:21 am

I thought dwBytesRead would tell you how many bytes you read actually... At least, provided ReadFile function is WinAPI standard function.

As to how pass the data through an event - it's really up to you provided you convert/store it right. You may use SetClientData() if you're afraid it won't fit into integer. Just remember to sotre it right, e.g. not delete it while you still need it.
win xp pro sp3/VS Express 2008/MinGW;
win Vista Ultimate/VS 2005;
Debian Lenny/gcc/cegcc-mingw32ce;
wxWidgets-2.8.9 w/wxWinCE;

Nathan
Experienced Solver
Experienced Solver
Posts: 83
Joined: Sat May 13, 2006 2:22 pm
Location: United States
Contact:

Post by Nathan » Wed Jan 07, 2009 1:27 am

Alrighty, it appears to be working now! Thanks for the help :D

I'll look into using "dwBytesRead", it might work I just haven't tried it.

Here's what I've got now:

Code: Select all

void *MyThread::Entry()
{
	const int numBytes = 1; // Set number of bytes to read
	while(1)
	{
		char szBuff[numBytes + 1] = {0}; // RESET BUFFER EACH LOOP, otherwise, if no new data, same buffer will be sent with event
		DWORD dwBytesRead = 0;			 // The number of bytes ACTUALLY read get stored here
		if(!ReadFile(hSerial, szBuff, numBytes, &dwBytesRead, NULL))
		{
			wxMessageBox(wxT("Error Reading File (COM Port)\nError: L104")); //error occurred. Report to user.
			wxMessageBox(wxT("Stopping the thread.. You will need to restart the COM port to continue debugging"));
			Exit();
		}

		if(!szBuff[0] == 0) // Don't create event unless there's new data, now wouldn't that be wasteful?
		{
			
			wxCommandEvent event( wxEVT_SERIAL, ID_SERIAL );
			//event.SetString( wxString(szBuff,wxConvUTF8) );
			event.SetInt((int)szBuff[0]);
			wxPostEvent( m_frame, event ); // m_frame is the pointer to the parent class 
		}
		else
		{
			//wxMessageBox(wxT("Empty"));
		}
	}
    return NULL;
}
It's not perfect, but it's working!

Nathan
Experienced Solver
Experienced Solver
Posts: 83
Joined: Sat May 13, 2006 2:22 pm
Location: United States
Contact:

Post by Nathan » Wed Jan 07, 2009 1:29 am

I know I just marked this topic as "solved", but one more question.

Do I need to have the "szBuff" be an array of two bytes so the null terminator can be there, or can I just have it be a single byte?

Post Reply