Stepping Through Lines In A Buffer

This is a discussion on Stepping Through Lines In A Buffer within the C Programming forums, part of the General Programming Boards category; Hello, I'm trying to write a small POP3 mail client, but although the basic mechanism works message retrieval is haphazard ...

  1. #1
    Registered /usr
    Join Date
    Aug 2001
    Location
    Newport, South Wales, UK
    Posts
    1,266

    Stepping Through Lines In A Buffer

    Hello,

    I'm trying to write a small POP3 mail client, but although the basic mechanism works message retrieval is haphazard at best. It usually gets through about 50 or so messages before hitting one that it can't fully read through. Here's a generalised version of the algorithm I'm using, which scans through each line:-
    Code:
    // First packet that's received for a message, reset the counter
    g_ulMsgRead = 0;
    
    szLine = g_szBuffer;
    while (szLine)
    {
        // Find the end of the current line
        szLineEnd = strstr(szLine, "\r\n");
        if (szLineEnd)
        {
            szLineEnd += 2;
            // Add line end - line start to the counter
            g_ulMsgRead += (szLineEnd - szLine);
        }
        else // Add the end of the buffer - line start to counter
            g_ulMsgRead += ((g_szBuffer + nBytesRead) - szLine);
    
        // If we've read the length of the message, finish
        if (g_ulMsgRead >= g_ulSize)
        {
            bFinished = 1;
            break;
        }
    
        szLine = szLineEnd;
    }
    Either packet splitting is causing this to go wrong somewhere or I need a better reference than the oddly-light RFC 1939.

  2. #2
    ATH0 quzah's Avatar
    Join Date
    Oct 2001
    Posts
    14,826
    Code:
    g_ulMsgRead += (szLineEnd - szLine);
    Why are you subtracting a size from a pointer?


    Quzah.
    Hope is the first step on the road to disappointment.

  3. #3
    Registered /usr
    Join Date
    Aug 2001
    Location
    Newport, South Wales, UK
    Posts
    1,266
    They're both pointers.
    szLine either points to the same place as the packet buffer (g_szBuffer) or to where szLineEnd pointed to last.
    szLineEnd is always the result of a strstr() call, which returns a pointer to somewhere or NULL.

  4. #4
    Frequently Quite Prolix dwks's Avatar
    Join Date
    Apr 2005
    Location
    Canada
    Posts
    8,048
    > a pointer to somewhere or NULL.

    What do you think happens when it's NULL?
    dwk

    Seek and ye shall find. quaere et invenies.

    "Simplicity does not precede complexity, but follows it." -- Alan Perlis
    "Testing can only prove the presence of bugs, not their absence." -- Edsger Dijkstra
    "The only real mistake is the one from which we learn nothing." -- John Powell


    Other boards: DaniWeb, TPS
    Unofficial Wiki FAQ: cpwiki.sf.net

    My website: http://dwks.theprogrammingsite.com/
    Projects: codeform, xuni, atlantis, nort, etc.

  5. #5
    Registered /usr
    Join Date
    Aug 2001
    Location
    Newport, South Wales, UK
    Posts
    1,266
    If it's NULL it doesn't get to that line, it simply adds the difference between the current position and the end of the packet to the counter. The while loop is subsequently broken out of and it waits for another packet.

  6. #6
    ATH0 quzah's Avatar
    Join Date
    Oct 2001
    Posts
    14,826
    Stop with the "generalized version", and post your actual code. Also, what do you mean "it can't get through"? What does it do?


    Quzah.
    Hope is the first step on the road to disappointment.

  7. #7
    Frequently Quite Prolix dwks's Avatar
    Join Date
    Apr 2005
    Location
    Canada
    Posts
    8,048
    Code:
        // Find the end of the current line
        szLineEnd = strstr(szLine, "\r\n");
        if (szLineEnd)
        {
            szLineEnd += 2;
            // Add line end - line start to the counter
            g_ulMsgRead += (szLineEnd - szLine);
        }
    Could you use strlen() there?
    dwk

    Seek and ye shall find. quaere et invenies.

    "Simplicity does not precede complexity, but follows it." -- Alan Perlis
    "Testing can only prove the presence of bugs, not their absence." -- Edsger Dijkstra
    "The only real mistake is the one from which we learn nothing." -- John Powell


    Other boards: DaniWeb, TPS
    Unofficial Wiki FAQ: cpwiki.sf.net

    My website: http://dwks.theprogrammingsite.com/
    Projects: codeform, xuni, atlantis, nort, etc.

  8. #8
    Registered /usr
    Join Date
    Aug 2001
    Location
    Newport, South Wales, UK
    Posts
    1,266
    dwks: not really, there would need to be a null character there and the only one is at the end of the buffer, as you shall see.

    quzah: whatever my baby wants

    This is from the FD_READ response of an ansynchronous Winsock notification, in its entirety. Yes there is duplicate code. Sue me.
    Code:
    int g_iStatus = 1;
    char g_szBuffer[2048];
    unsigned long g_ulCount, g_ulCurMsg, g_ulMsgRead, g_ulSize;
    HWND g_hwndLV, g_hwndEdit, g_hwndStatus;
    SOCKET g_Socket;
    
    case FD_READ:
    {
        char *szLine, *szLineEnd, szTemp[256];
        int nBytesRead;
    
        SendMessage(g_hwndStatus, SB_SETTEXT, 0, (LPARAM)"Receiving");
        nBytesRead = recv(g_Socket, g_szBuffer, 2047, 0);
        g_szBuffer[nBytesRead] = '\0';
        // positive response?
        if (g_szBuffer[0] == '+')
        {
            switch(g_iStatus)
            {
                case 1:
                {
                    SendMessage(g_hwndEdit, EM_REPLACESEL, 0, (LPARAM)g_szBuffer);
                    wsprintf(szTemp, "USER \r\n"); // stick a username in here
                    send(g_Socket, szTemp, strlen(szTemp), 0);
                    g_iStatus = 2;
                    break;
                }
                case 2:
                {
                    SendMessage(g_hwndEdit, EM_REPLACESEL, 0, (LPARAM)g_szBuffer);
                    wsprintf(szTemp, "PASS \r\n"); // password here
                    send(g_Socket, szTemp, strlen(szTemp), 0);
                    g_iStatus = 3;
                    break;
                }
                case 3:
                {
                    SendMessage(g_hwndEdit, EM_REPLACESEL, 0, (LPARAM)g_szBuffer);
                    wsprintf(szTemp, "STAT\r\n");
                    send(g_Socket, szTemp, strlen(szTemp), 0);
                    g_iStatus = 4;
                    break;
                }
                case 4:
                {
                    SendMessage(g_hwndEdit, EM_REPLACESEL, 0, (LPARAM)g_szBuffer);
                    sscanf(g_szBuffer, "+OK %lu %lu", &g_ulCount, &g_ulSize);
                    g_ulCurMsg = g_ulCount;
                    wsprintf(szTemp, "LIST %lu\r\n", g_ulCurMsg);
                    send(g_Socket, szTemp, strlen(szTemp), 0);
                    g_iStatus = 5;
                    break;
                }
                case 5:
                {
                    SendMessage(g_hwndEdit, EM_REPLACESEL, 0, (LPARAM)g_szBuffer);
                    sscanf(g_szBuffer, "+OK %lu %lu", &g_ulCurMsg, &g_ulSize);
                    wsprintf(szTemp, "RETR %lu\r\n", g_ulCurMsg--);
                    send(g_Socket, szTemp, strlen(szTemp), 0);
                    g_iStatus = 6;
                    break;
                }
                case 6:
                {
                    szLine = strstr(g_szBuffer, "\r\n"); // Ignore the "+OK" line
                    if (szLine)
                    {
                        szLine += 2;
                        g_ulMsgRead = 0; // reset counter on initial packet
                        while (szLine)
                        {
                            // Find the end of the current line
                            szLineEnd = strstr(szLine, "\r\n");
                            if (szLineEnd)
                            {
                                szLineEnd += 2;
                                // Add line end - line start to the counter
                                g_ulMsgRead += (szLineEnd - szLine);
                            }
                            else // Add the end of the buffer - line start to counter
                                g_ulMsgRead += ((g_szBuffer + nBytesRead) - szLine);
    
                            // If we've read the length of the message, finish
                            if (g_ulMsgRead >= g_ulSize)
                            {
                                if (g_ulCurMsg)
                                {
                                    wsprintf(szTemp, "LIST %lu\r\n", g_ulCurMsg);
                                    send(g_Socket, szTemp, strlen(szTemp), 0);
                                    g_iStatus = 5;
                                }
                                else
                                {
                                    wsprintf(szTemp, "QUIT\r\n");
                                    send(g_Socket, szTemp, strlen(szTemp), 0);
                                    g_iStatus = 7;
                                }
    
                                break;
                            }
    
                            szLine = szLineEnd;
                        }
    
                    }
    
                    break;
                }
                case 7:
                {
                    wsprintf(szTemp, "You have %lu new messages (%lu octets).", g_ulCount, g_ulSize);
                    MessageBox(hwndDlg, szTemp, "New Messages", MB_ICONINFORMATION);
                    break;
                }
    
            }
    
        }
        else
        {
            // data?
            if (g_iStatus == 6)
            {
                szLine = g_szBuffer;
                while (szLine)
                {
                    // Find the end of the current line
                    szLineEnd = strstr(szLine, "\r\n");
                    if (szLineEnd)
                    {
                        szLineEnd += 2;
                        // Add line end - line start to the counter
                        g_ulMsgRead += (szLineEnd - szLine);
                    }
                    else // Add the end of the buffer - line start to counter
                        g_ulMsgRead += ((g_szBuffer + nBytesRead) - szLine);
    
                    // If we've read the length of the message, finish
                    if (g_ulMsgRead >= g_ulSize)
                    {
                        if (g_ulCurMsg)
                        {
                            wsprintf(szTemp, "LIST %lu\r\n", g_ulCurMsg);
                            send(g_Socket, szTemp, strlen(szTemp), 0);
                            g_iStatus = 5;
                        }
                        else
                        {
                            wsprintf(szTemp, "QUIT\r\n");
                            send(g_Socket, szTemp, strlen(szTemp), 0);
                            g_iStatus = 7;
                        }
    
                        break;
                    }
    
                    szLine = szLineEnd;
               }
               else // bad stuff, just print and curse repeatedly
                   SendMessage(g_hwndEdit, EM_REPLACESEL, 0, (LPARAM)g_szBuffer);
    
            }
    
            break;
        }
    
    }

  9. #9
    ATH0 quzah's Avatar
    Join Date
    Oct 2001
    Posts
    14,826
    You still haven't said what "doesn't get through it" means. Does it hang? Does it crash? What exactly?


    Quzah.
    Hope is the first step on the road to disappointment.

  10. #10
    Registered /usr
    Join Date
    Aug 2001
    Location
    Newport, South Wales, UK
    Posts
    1,266
    Okay, from a spot of testing I did last night, in some very particular cases g_ulMsgRead never equals or exceeds g_ulSize, so strstr returns NULL, it drops out of the loop and waits for another packet that never comes. I'm mis-counting somewhere...

  11. #11
    ATH0 quzah's Avatar
    Join Date
    Oct 2001
    Posts
    14,826
    You can cash your program right here:
    Code:
                    if (szLine)
                    {
                        szLine += 2;
                        g_ulMsgRead = 0; // reset counter on initial packet
                        while (szLine)
                        {
    Give the following series of characters \r\n\0 and you will wind up with the pointer not being NULL, but you'll be at the end of the string. Then you'll run off past the end of your buffer or string or what have you.


    Quzah.
    Hope is the first step on the road to disappointment.

  12. #12
    Gawking at stupidity
    Join Date
    Jul 2004
    Location
    Oregon, USA
    Posts
    3,175
    Umm...it's addition and subtraction.
    If you understand what you're doing, you're not learning anything.

  13. #13
    Gawking at stupidity
    Join Date
    Jul 2004
    Location
    Oregon, USA
    Posts
    3,175
    Yup, and so is szLine. I thought you knew all about pointers
    If you understand what you're doing, you're not learning anything.

  14. #14
    Gawking at stupidity
    Join Date
    Jul 2004
    Location
    Oregon, USA
    Posts
    3,175
    Look at the code, man!
    Code:
                szLine = g_szBuffer;
                while (szLine)
                {
                    // Find the end of the current line
                    szLineEnd = strstr(szLine, "\r\n");
                    if (szLineEnd)
                    {
                        szLineEnd += 2;
                        // Add line end - line start to the counter
                        g_ulMsgRead += (szLineEnd - szLine);
                    }
    ...
                    szLine = szLineEnd;
               }
    If you understand what you're doing, you're not learning anything.

  15. #15
    Gawking at stupidity
    Join Date
    Jul 2004
    Location
    Oregon, USA
    Posts
    3,175
    What's with your documentationaphobia?

    From the man page:
    SYNOPSIS
    #include <string.h>

    char *strstr(const char *haystack, const char *needle);

    DESCRIPTION
    The strstr() function finds the first occurrence of the
    substring needle in the string haystack. The terminating
    `\0' characters are not compared.

    RETURN VALUE
    The strstr() function returns a pointer to the [doublebold]beginning
    of the substring[/doublebold], or NULL if the substring is not found.
    If you understand what you're doing, you're not learning anything.

Page 1 of 2 12 LastLast
Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Multithreading (flag stopping a thread, ring buffer) volatile
    By ShwangShwing in forum C Programming
    Replies: 3
    Last Post: 05-19-2009, 08:27 AM
  2. writing a pack-style function, any advices?
    By isaac_s in forum C Programming
    Replies: 10
    Last Post: 07-08-2006, 09:09 PM
  3. Having Buffer Problems With Overlapped I/O --
    By Sargera in forum C++ Programming
    Replies: 0
    Last Post: 02-07-2006, 04:46 PM
  4. recv multiple lines
    By TCM in forum Networking/Device Communication
    Replies: 11
    Last Post: 07-13-2004, 05:54 PM
  5. count only lines of code...
    By flightsimdude in forum C Programming
    Replies: 13
    Last Post: 09-23-2003, 08:08 PM

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21