|
|
Trying to get some words in a char...
Last post 12-11-2006, 3:53 PM by vloktboky. 8 replies.
-
12-10-2006, 4:00 PM |
-
Jary
-
-
-
Joined on 11-21-2006
-
-
Posts 34
-
-
|
Trying to get some words in a char...
Hey guys, I have a new problem for you.
I'm getting something like this in my recv:
(This represents buf_str seen a little lower. It is type char, and it's a pointer).
I need to get PRIVMSG and #CHANNEL, and only those, in a var, or vector, or anything (I don't know which is best), to check letter if ((a == PRIVMSG) && (b == #CHANNEL))
for example.
My code is:
int word = 0, letter = 0;
char *word1 = NULL;
while ((buf_str[letter] != '\0') && (fconnect)) {
if ((buf_str[letter] == ' ') && (word != 3)) {
char delimit[] = " ";
word1 = strtok(buf_str, delimit);
++word;
if (word1 != NULL) { word1 = strtok(NULL, delimit); }
while ((word != 3) && (word1 != NULL)) {
cout << "I have a word: " << word1 << endl << endl;
++word;
word1 = strtok(NULL, delimit);
}
}
++letter;
}
I have 2 problem with that:
A) I need buf_str to be left unchange after the while, but it is changed to Jary!Jary@wanadoo.fr.
B) I need to have a variable, or a vector containing all the 2 words, but I don't know how to make it with a variable, lika var1 and var2,, but I do know how to do with a vector though, wish push_back. I don't know which is best btw, if I use vector, I would use: word.push_back(strtok(buf_str, delimit))
, but i don't know which way is best, to compare it after: if ((a == PRIVMSG...)
I hope my message is clear, and doesn't confuse you. Otherwise just ask me.
Thanks a lot in advance.
|
|
-
12-10-2006, 6:32 PM |
-
vloktboky
-
-
-
Joined on 11-27-2006
-
Covington, KY
-
Posts 253
-
-
|
Re: Trying to get some words in a char...
I get the impression that you are building an IRC client. And
with this kind of project, you are going to be executing this bit of
code everytime a message is received. This can occur a lot and,
given the fact that dealing with strings can quickly turn into a
nightmare, you are going to want code that will execute relatively
quickly and with as least amount of memory management as
possible. The best way to get what you want and to achieve this
result is to not alter the string that contains your received message
and, instead, to calculate the offset into the string and the length of
the pieces of data and store this.
Below is some code I wrote up real fast that will do this for
you. Keep in mind that the code below is going to find the
offsets into the command string where the operator and operands are
located. The for loop will iterate through each character in the
string looking for a space. Once found, it will do the necessary
calculations and store the current location depending on what has
already been found. Since we go from left to right, the operator
("PRIVMSG", "JOIN", etc) will be the first thing found, followed by the
first and second operands. The nested if statements reflect
this. Once one has been found, the difference in the last found
and current offsets are used to store the lengths.
Now because we are storing the offsets and not creating clones of the
data, these memory addresses are local to the command string (in this
case szMsg). That means that if szMsg goes out of scope, these
addresses become invalid. Furthermore, any manipulation done to
szMsg may cause these offsets to become invalid, so be careful.
By doing this, we are not taking up precious execution time to allocate
dynamic memory from the heap and clone already given data. Use
the lengths and memcmps!
char* szMsg = "Jary!Jarry@wanadoo.fr PRIVMSG #CHANNEL Hello, It's me, how are you ?";
char *pOperator = NULL; // Event of this message ("PRIVMSG")
char *pOperand1 = NULL; // First operand of the message (channel, name, etc)
char *pOperand2 = NULL; // Second operand of the message (text, etc)
int nOperatorLength = 0, nOperand1Length = 0, nOperand2Length = 0;
// Extract data from message. "szMsg" holds the message received.
char *pOffset = NULL; // Need this after the loop
for (pOffset = szMsg; *pOffset != '\0'; pOffset += sizeof(char))
{
if (*pOffset != ' ') continue; // Keep going until we hit a space
if (pOperator == NULL)
{
// Extract operator
pOperator = (pOffset+sizeof(char));
continue;
}
else if (pOperand1 == NULL)
{
// Calculate offset difference to get length of operator
nOperatorLength = *((int*)(&pOffset))-*((int*)(&pOperator));
// Extract first operand
pOperand1 = (pOffset+sizeof(char));;
continue;
}
else if (pOperand2 == NULL)
{
// Calculate offset difference to get length of first operand
nOperand1Length = *((int*)(&pOffset))-*((int*)(&pOperand1));
// Extract second operand
pOperand2 = (pOffset+sizeof(char));;
continue;
}
} if (pOperand2 != NULL)
{
// Calculate offset difference to get length of second operand
nOperand2Length = *((int*)(&pOffset))-*((int*)(&pOperand2));
}
else if (pOperand1 != NULL)
{
// Calculate offset difference to get length of first operand
nOperand1Length = *((int*)(&pOffset))-*((int*)(&pOperand1));
}
else if (pOperator != NULL)
{
// Calculate offset difference to get length of operator
nOperatorLength = *((int*)(&pOffset))-*((int*)(&pOperator));
}
// TODO Specific code to deal with operator and operands
// To check if operator is PRIVMSG:
if (memcmp(pOperator, "PRIVMSG", nOperatorLength) == 0)
{
// TODO Handle PRIVMSG. Similar checks on operands.
// Example output message. Use the lengths!
char szBuffer[256];
strcpy(szBuffer, "Private message to channel \"");
strncat(szBuffer, pOperand1, nOperand1Length);
strcat(szBuffer, "\": ");
strncat(szBuffer, pOperand2, nOperand2Length);
std::cout << szBuffer << '\n';
}
Any questions, just let me know.
|
|
-
12-10-2006, 9:45 PM |
-
vloktboky
-
-
-
Joined on 11-27-2006
-
Covington, KY
-
Posts 253
-
-
|
Re: Trying to get some words in a char...
FYI: I updated the code listed previously for some error prevention.
|
|
-
12-11-2006, 1:44 AM |
-
Jary
-
-
-
Joined on 11-21-2006
-
-
Posts 34
-
-
|
Re: Trying to get some words in a char...
I finally found a solution, by checking the condition inside the while, so i don't mind if buf_str is changed, and i don't set a variable, and I gain time. But I thank you for your code. I see you use sizeof, I think it will make me gain time that checking char by char. I'll try to change my code to yours. My actual code is:
*Big update a few posts down*
while (buf_str[letter] != '\0') {
if (buf_str[letter] == ' ') {
nameadd = strtok(buf_str, delimit);
word1 = strtok(NULL, delimit);
if (strstr(nameadd, "PING")) {
string word11 = word1;
string r = string( "PONG ") + word11;
cout << endl << endl << endl << r << endl << endl;
char e[15];
r.copy(e,r.size());
cout << endl << endl << endl << e << endl << endl;
send(sock, e, ( int) strlen(e), 0);
cout << endl << e;
}
else if (strstr(word1, "PRIVMSG")) {
word2 = strtok(NULL, delimit);
if (strstr(word2, "Bot-Request")) {
word3 = strtok(NULL, delimit);
if (strstr(word3, "VERSION") || strstr(word3, "MOTFV")) {
char *delim = ":!";
char *snick = strtok(nameadd, delim);
p = "NOTICE %s :VERSION Eonora bot coded by Jary\r\n";
char e[15];
sprintf(e, p, snick);
send(sock, e, ( int) strlen(e), 0);
cout << endl << e;
}
else {
char *delim = ":!";
char *snick = strtok(nameadd, delim);
p = "NOTICE %s :Unknown command. Try: /msg Bot-Request showcommands\r\n";
char e[15];
sprintf(e, p, snick);
send(sock, e, ( int) strlen(e), 0);
cout << endl << e;
}
}
}
else if (strstr(word1, "366")) {
word2 = strtok(NULL, delimit);
word3 = strtok(NULL, delimit);
if (strstr(word3, "#Jarrod.Bots")) {
if (!joined) {
p = "PRIVMSG #Jarrod.Bots :Hello, I\'m the Request-Bot System! Type: /msg Bot-Request Requesthelp to request a bot.\r\n";
send(sock, p, ( int) strlen(p), 0);
cout << endl << p;
joined = 1;
}
}
}
}
++letter;
}
Any advice are welcome. The ping stuff doesn't work btw, r is set correctly, but e isn't when I use the r.copy before sending it :(
I'll work on the code and post it again, with the changes to yours. Thanks again
|
|
-
12-11-2006, 1:56 AM |
-
Jary
-
-
-
Joined on 11-21-2006
-
-
Posts 34
-
-
|
Re: Trying to get some words in a char...
I have some trouble with your code, already lol (sorry i'm still a beginner).
I understand the for loop and what's inside, but I don't understand why you added this after:
if (pOperand2 != NULL) { // Calculate offset difference to get length of second operand nOperand2Length = *((int*)(&pOffset))-*((int*)(&pOperand2)); } else if (pOperand1 != NULL) { // Calculate offset difference to get length of first operand nOperand1Length = *((int*)(&pOffset))-*((int*)(&pOperand1)); } else if (pOperator != NULL) { // Calculate offset difference to get length of operator nOperatorLength = *((int*)(&pOffset))-*((int*)(&pOperator)); }
It looks to me that everything is already set in the loop, isn't it ?
|
|
-
12-11-2006, 2:41 AM |
-
Jary
-
-
-
Joined on 11-21-2006
-
-
Posts 34
-
-
|
Re: Trying to get some words in a char...
When I get a message, from IRC, a while that i haven't posted it, but I assume you understood it, was checking for '\0', and so making each line.
So I tought, why not remove the While and if:
while (buf_str[letter] != '\0') {
if (buf_str[letter] == ' ') {
So I just removed then, because I know the server will send me at least 2 words when connected, so they are useless, and make the code slower. I should just check for spaces per line, but the tokenizer: strtok, seems to do it.
Tell me if it is alright to do, the final code is:
char *nameadd;
char *word1;
char *word2;
char *word3;
char delimit[] = " ";
nameadd = strtok(buf_str, delimit);
word1 = strtok(NULL, delimit);
if (strstr(nameadd, "PING")) {
string word11 = word1;
string r = string( "PONG ") + word11;
cout << endl << endl << endl << r << endl << endl;
r.copy(p,r.size());
send(sock, p, ( int) strlen(p), 0);
cout << endl << p;
}
else if (strstr(word1, "PRIVMSG")) {
word2 = strtok(NULL, delimit);
if (strstr(word2, "Bot-Request")) {
word3 = strtok(NULL, delimit);
if (strstr(word3, "VERSION") || strstr(word3, "MOTFV")) {
char *delim = ":!";
char *snick = strtok(nameadd, delim);
p = "NOTICE %s :VERSION Eonora bot coded by Jary\r\n";
char e[15];
sprintf(e, p, snick);
send(sock, e, ( int) strlen(e), 0);
cout << endl << e;
}
else {
char *delim = ":!";
char *snick = strtok(nameadd, delim);
p = "NOTICE %s :Unknown command. Try: /msg Bot-Request showcommands\r\n";
char e[15];
sprintf(e, p, snick);
send(sock, e, ( int) strlen(e), 0);
cout << endl << e;
}
}
}
else if (strstr(word1, "366")) {
word2 = strtok(NULL, delimit);
word3 = strtok(NULL, delimit);
if (strstr(word3, "#Jarrod.Bots") && !joined) {
p = "PRIVMSG #Jarrod.Bots :Hello, I\'m the Request-Bot System! Type: /msg Bot-Request Requesthelp to request a bot.\r\n";
send(sock, p, ( int) strlen(p), 0);
cout << endl << p;
joined = 1;
}
}
Note: The ping function isn't working yet, I get my r correctly: PONG :my....
but p gives a few weird characters.
I checked each value:
- word1 0x0035936d ":mistral.il.us.zirc.org" char *
+ word11 ":mistral.il.us.zirc.org" std::basic_string<char,std::char_traits<char>,std::allocator<char> >
Then it looks like r.copy crashes, with "violating access..." . I hope this screenshot will help: 
There is a little tiny problem with that code: it checks with strstr because when I use something like: "word3 == #Jarrod.Bots" it doesn't respond, I guess word3 must be like \0 at the end, but still it doesn't read on it. Just checked the value of word1, it's value is: - word1 0x00359306 "PRIVMSG" char * so i guess it's normal, I didn't check for the hexadencial code, so it will be strstr.
I'm sorry I posted so much. Please take your time.
Thanks again
|
|
-
12-11-2006, 10:15 AM |
-
vloktboky
-
-
-
Joined on 11-27-2006
-
Covington, KY
-
Posts 253
-
-
|
Re: Trying to get some words in a char...
The chain of if statements that follow the for loop ensure that the
correct lengths are computed, even if the instruction does not have two
exact operands. For example, if you are dealing with a PING
message, then you have no operands. Logic will ensure that the
last else if statement in this chain gets called which will set the
length of the operator. This same definition within the for loop
would have been passed up otherwise.
|
|
-
12-11-2006, 10:51 AM |
-
Jary
-
-
-
Joined on 11-21-2006
-
-
Posts 34
-
-
|
Re: Trying to get some words in a char...
I see what you mean. Thank you. I think my code is fine too, if you don't mind having a look sometime. I'll check to repair the ping function with this copy.
Okay now the ping work 
Everything is now working. You can check: http://img182.imageshack.us/my.php?image=botlogus0.jpg to see.
Thanks for your help vloktboky, you helped me much !
|
|
-
|
|
|