Welcome to RenEvo Sign in | Join | Help
in
Home Wiisis Blogs Forums Photos Downloads About

Trying to get some words in a char...

Last post 12-11-2006, 3:53 PM by vloktboky. 8 replies.
Sort Posts: Previous Next
  •  12-10-2006, 4:00 PM 339

    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 340 in reply to 339

    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 348 in reply to 340

    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 359 in reply to 348

    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 360 in reply to 359

    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 361 in reply to 360

    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 372 in reply to 361

    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 376 in reply to 372

    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 Smile

    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 !

  •  12-11-2006, 3:53 PM 391 in reply to 376

    Re: Trying to get some words in a char...

    Glad to hear.
View as RSS news feed in XML
Powered by Community Server, by Telligent Systems