C++ string parser for wpa_supplicant I have created a naive string parser for unsolicited wpa_supplicant messages.  I could potentially extend this in the future.  I am not sure if this is the best way to parse these kinds of messages.  I would prefer something resembling a switch statement but I am not sure I could do that without increasing code complexity.  I would like a more scalable solution though, in case I need to look for many different message types in the future.

Code:

#include &lt;stdio.h&gt;
#include &lt;string&gt;
#include &lt;map&gt;

#define DEBUG_PRINT printf

class wpa_monitor
{
    public:
        void handle_wpa_message( const std::string&amp; message );

    private:
        std::map&lt; std::string, std::string &gt; mac_ssid_association_map;
};

void wpa_monitor::handle_wpa_message( const std::string&amp; message )
{
    DEBUG_PRINT( "WPA event: '%s'\n", message.c_str() );
    size_t pos;

    pos = message.find( "Trying to associate with " );

    if( pos != std::string::npos )
    {
        std::string mac_substring = message.substr( pos + sizeof( "Trying to associate with " ) - 1 );
        std::string mac_addr = mac_substring.substr( 0, mac_substring.find( " " ) );

        if( mac_addr.empty() )
        {
            return;
        }

        pos = message.find( "SSID='" );

        if( pos == std::string::npos )
        {
            return;
        }

        std::string ssid_substring = message.substr( pos + sizeof( "SSID='" ) - 1 );
        std::string ssid = ssid_substring.substr( 0, ssid_substring.find( "'" ) );

        DEBUG_PRINT( "Associating mac_address '%s' with ssid '%s'\n", mac_addr.c_str(), ssid.c_str() );
        mac_ssid_association_map.insert( std::make_pair&lt; std::string, std::string &gt;( mac_addr, ssid ) );

        return;
    }

    pos = message.find( "CTRL-EVENT-CONNECTED - Connection to " );

    if( pos != std::string::npos )
    {
        std::string mac_substring = message.substr( pos + sizeof( "CTRL-EVENT-CONNECTED - Connection to " ) - 1 );
        std::string mac_addr = mac_substring.substr( 0, mac_substring.find( " " ) );

        if( mac_addr.empty() )
        {
            return;
        }

        std::map&lt; std::string, std::string &gt;::iterator it = mac_ssid_association_map.find( mac_addr );

        if( it != mac_ssid_association_map.end() )
        {
            DEBUG_PRINT( "We are now connected to ssid '%s'\n", it-&gt;second.c_str() );
        }

        return;
    }

    pos = message.find( "CTRL-EVENT-SCAN-RESULTS" );

    if( pos != std::string::npos )
    {
        //scan results ready
        DEBUG_PRINT( "Scan results are ready\n" );
        return;
    }
}


Example Output (personal data obfuscated):

WPA event: '&lt;3&gt;CTRL-EVENT-SCAN-STARTED '
WPA event: '&lt;3&gt;CTRL-EVENT-BSS-ADDED 0 00:00:00:00:00:00'
WPA event: '&lt;3&gt;CTRL-EVENT-BSS-ADDED 1 00:00:00:00:00:01'
WPA event: '&lt;3&gt;CTRL-EVENT-BSS-ADDED 2 00:00:00:00:00:02'
WPA event: '&lt;3&gt;CTRL-EVENT-SCAN-RESULTS '
Scan results are ready
WPA event: '&lt;3&gt;WPS-AP-AVAILABLE '
WPA event: '&lt;3&gt;Trying to associate with 00:00:00:00:00:00 (SSID='my_ssid' freq=5745 MHz)'
Associating mac_address '00:00:00:00:00:00' with ssid 'my_ssid'
WPA event: '&lt;3&gt;Associated with 00:00:00:00:00:00'
WPA event: '&lt;3&gt;CTRL-EVENT-SUBNET-STATUS-UPDATE status=0'
WPA event: '&lt;3&gt;WPA: Key negotiation completed with 00:00:00:00:00:00 [PTK=CCMP GTK=TKIP]'
WPA event: '&lt;3&gt;CTRL-EVENT-CONNECTED - Connection to 00:00:00:00:00:00 completed [id=1 id_str=]'
We are now connected to ssid 'my_ssid'
I'll make no comment on the use of C-style &lt;stdio.h&gt;, since that's likely an artefact of the surrounding code, rather than something you'd have written yourself.

A missing header and a typo/oversight

The header required for std::make_pair is &lt;utility&gt;.  Your implementation may have defined it as a side-effect of including &lt;map&gt;, but it's not portable to rely on that.

size_t pos ought to be std::size_t pos.

Test program

I managed to re-create some input from your sample output:

int main()
{
    static auto const messages = {
        "&lt;3&gt;CTRL-EVENT-SCAN-STARTED ",
        "&lt;3&gt;CTRL-EVENT-BSS-ADDED 0 00:00:00:00:00:00",
        "&lt;3&gt;CTRL-EVENT-BSS-ADDED 1 00:00:00:00:00:01",
        "&lt;3&gt;CTRL-EVENT-BSS-ADDED 2 00:00:00:00:00:02",
        "&lt;3&gt;CTRL-EVENT-SCAN-RESULTS ",
        "&lt;3&gt;WPS-AP-AVAILABLE ",
        "&lt;3&gt;Trying to associate with 00:00:00:00:00:00 (SSID='my_ssid' freq=5745 MHz)",
        "&lt;3&gt;Associated with 00:00:00:00:00:00",
        "&lt;3&gt;CTRL-EVENT-SUBNET-STATUS-UPDATE status=0",
        "&lt;3&gt;WPA: Key negotiation completed with 00:00:00:00:00:00 [PTK=CCMP GTK=TKIP]",
        "&lt;3&gt;CTRL-EVENT-CONNECTED - Connection to 00:00:00:00:00:00 completed [id=1 id_str=]",
    };

    wpa_monitor monitor;

    for (auto m: messages)
        monitor.handle_wpa_message(m);
}


Naming

I avoid names that include their type, as it can be confusing if you later change that type.  So I'd call the map mac_to_ssid instead.  That also has the benefit of being shorter, so easy to type and to read.

Extensibility

You'll find that a single large method gets harder to navigate as it gets bigger.  As hinted in another answer, it makes sense to delegate to a bunch of simple methods that each handle a single case.  You could iterate through a vector, but I'd stick to something simple like this:

class wpa_monitor
{
public:
    bool handle_wpa_message(const std::string&amp; message);

private:
    std::map&lt;std::string, std::string&gt; mac_ssid_association_map = {};

    bool handle_associate(const std::string&amp; message);
    bool handle_connected(const std::string&amp; message);
    bool handle_scanresult(const std::string&amp; message);
};




bool wpa_monitor::handle_wpa_message(const std::string&amp; message)
{
    DEBUG_PRINT("WPA event: '%s'\n", message.c_str());

    return handle_associate(message)
        || handle_connected(message)
        || handle_scanresult(message);
}


Now we can look at each matcher in turn.

Refactor some common code

We repeatedly search for a string and take an interest in its end, like this:

auto pos = message.find("Trying to associate with ");
if (pos == std::string::npos)
    return false;

std::string mac_substring = message.substr(pos + sizeof "Trying to associate with " - 1);


Obviously there's scope for error if we don't keep the two copies of the string in agreement.  Instead, we can write a small function to do this:

static std::size_t find_end(const std::string&amp; s, const std::string&amp; substr)
{
    auto pos = s.find(substr);
    if (pos != std::string::npos)
        pos += substr.size();
    return pos;
}


That makes the caller simpler and more robust:

auto pos = find_end(message, "Trying to associate with ");
if (pos == std::string::npos)
    return false;

auto const mac_substring = message.substr(pos);


Actually, that's not really the MAC substring, as it continues to the end of the string.  We really want another helper, accepting a termination character:

static std::string find_in_delimiters(const std::string&amp; s,
                                      const std::string&amp; open, const char close)
{
    auto start = s.find(open);
    if (start == std::string::npos)
        return {};
    start += open.size();

    auto end = s.find(close, start);
    if (end == std::string::npos)
        return {};

    return s.substr(start, end-start);
}


And we simplify the callers even more:

    auto mac_addr = find_in_delimiters(message, "Trying to associate with ", ' ');
    if (mac_addr.empty()) {
        return false;
    }


More on make_pair()

I get a failure to compile, as GCC seems to want rvalue references for make_pair&lt;string,string&gt;().  I could resolve that with a std::move() like this:

    mac_ssid_association_map.insert( std::make_pair&lt; std::string, std::string &gt;( std::move(mac_addr), std::move(ssid) ) );


However, we can let template type deduction do its thing:

    mac_ssid_association_map.insert(std::make_pair(std::move(mac_addr), std::move(ssid)));


Or even just:

    mac_ssid_association_map.insert({std::move(mac_addr), std::move(ssid)});


Use auto instead of exact iterator types

Here's a place where changing the map type could be a maintenance headache:

    std::map&lt; std::string, std::string &gt;::iterator it = mac_ssid_association_map.find( mac_addr );


We can use auto, which also makes it more readable:

    auto it = mac_ssid_association_map.find(mac_addr);




My version

#include &lt;cstdio&gt;
#include &lt;string&gt;
#include &lt;map&gt;
#include &lt;utility&gt;

#define DEBUG_PRINT std::printf

class wpa_monitor
{
public:
    bool handle_wpa_message(const std::string&amp; message);

private:
    std::map&lt;std::string, std::string&gt; mac_to_ssid = {};

    bool handle_associate(const std::string&amp; message);
    bool handle_connected(const std::string&amp; message);
    bool handle_scanresult(const std::string&amp; message);
};




// Helper method - returns substring of s contained between
// open and close, or empty if not matched
static std::string find_in_delimiters(const std::string&amp; s,
                                      const std::string&amp; open, const char close)
{
    auto start = s.find(open);
    if (start == s.npos)
        return {};
    start += open.size();

    auto end = s.find(close, start);
    if (end == s.npos)
        return {};

    return s.substr(start, end-start);
}




// Handlers for specific message types

bool wpa_monitor::handle_associate(const std::string&amp; message)
{
    auto mac_addr = find_in_delimiters(message, "Trying to associate with ", ' ');
    if (mac_addr.empty())
        return false;

    auto ssid = find_in_delimiters(message, "SSID='", '\'');
    if (ssid.empty())
        return false;

    DEBUG_PRINT("Associating mac_address '%s' with ssid '%s'\n", mac_addr.c_str(), ssid.c_str());
    mac_to_ssid.insert({std::move(mac_addr), std::move(ssid)});
    return true;
}

bool wpa_monitor::handle_connected(const std::string&amp; message)
{
    auto mac_addr = find_in_delimiters(message, "CTRL-EVENT-CONNECTED - Connection to ", ' ');
    if (mac_addr.empty())
        return false;

    auto it = mac_to_ssid.find(mac_addr);
    if (it != mac_to_ssid.end()) {
        DEBUG_PRINT("We are now connected to ssid '%s'\n", it-&gt;second.c_str());
    }

    return true;
}

bool wpa_monitor::handle_scanresult(const std::string&amp; message)
{
    auto pos = message.find("CTRL-EVENT-SCAN-RESULTS");
    if (pos == message.npos)
        return false;

    //scan results ready
    DEBUG_PRINT("Scan results are ready\n");
    return true;
}




// Test program

int main()
{
    static auto const messages = {
        "&lt;3&gt;CTRL-EVENT-SCAN-STARTED ",
        "&lt;3&gt;CTRL-EVENT-BSS-ADDED 0 00:00:00:00:00:00",
        "&lt;3&gt;CTRL-EVENT-BSS-ADDED 1 00:00:00:00:00:01",
        "&lt;3&gt;CTRL-EVENT-BSS-ADDED 2 00:00:00:00:00:02",
        "&lt;3&gt;CTRL-EVENT-SCAN-RESULTS ",
        "&lt;3&gt;WPS-AP-AVAILABLE ",
        "&lt;3&gt;Trying to associate with 00:00:00:00:00:00 (SSID='my_ssid' freq=5745 MHz)",
        "&lt;3&gt;Associated with 00:00:00:00:00:00",
        "&lt;3&gt;CTRL-EVENT-SUBNET-STATUS-UPDATE status=0",
        "&lt;3&gt;WPA: Key negotiation completed with 00:00:00:00:00:00 [PTK=CCMP GTK=TKIP]",
        "&lt;3&gt;CTRL-EVENT-CONNECTED - Connection to 00:00:00:00:00:00 completed [id=1 id_str=]",
    };

    wpa_monitor monitor;

    for (auto m: messages)
        monitor.handle_wpa_message(m);
}