"0000:0e:00.0" does not seem to be grabbed properly

From:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
#include <iostream>

using namespace std;

#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <fstream>
#include <string>
#include <cstring>
#include <stdexcept>

using namespace std;
string GetStdoutFromCommand(string);
string get_iface_name(string);

int main()
{
    string slotPCIe = "0000:0e:00.0";
    get_iface_name(slotPCIe);
    return 0;
}

string GetStdoutFromCommand(string cmd)                     //copied this function from interwebs
{                                                           //don't really understand it yet
    string data;
    FILE * stream;
    const int max_buffer = 256;
    char buffer[max_buffer];
    cmd.append(" 2>&1");

    stream = popen(cmd.c_str(), "r");
    if (stream)
    {
        while (!feof(stream)) if (fgets(buffer, max_buffer, stream) != NULL) data.append(buffer);
        pclose(stream);
    }
    return data;
}
string get_iface_name (string pcie_slot)
{
    string cmd = "systool -c net";
    string string_body = GetStdoutFromCommand(cmd);      //grab the output of the above bash command to use as a search_body
    cout << string_body << "\n" << endl;                 //confirm that output to user by printing it to console
    string delim = " ";                             //variable setting the delimiter for the search
    cout << "delim = " << delim << endl;            //confirm that setting to user by printing it to console
    string slotPCIe = "0000:0e:00.0";               //variable setting the id for the expresscard
    cout << "slotPCIe = " << slotPCIe << endl;      //confirm that setting to user by printing it to console
    string deviceTYPE = "0280:";                    //variable setting the id for the device type
    cout << "deviceTYPE = " << deviceTYPE << endl;  //confirm that setting to user by printing it to console
    string DWA_643 = "168c:0024";                   //variable setting the id for the D-Link DWA_643
    cout << "DWA_643 = " << DWA_643 << endl;        //confirm that setting to user by printing it to console
    int i = 150, t=0, c=0;
    string token[i];                                //array to store the slices of the string_body

    auto start = 0U;                                //I don't really understand this line
    auto end = string_body.find(delim);             //I don't really understand this line

    while (end != std::string::npos)                //This while loop scans through the string body
    {                                               //and slices out each substring between the delimiter
            token[t] = string_body.substr(start, end - start);
            cout << token[t];
            start = end + delim.length();
            end = string_body.find(delim, start);
            t++;
            c++;
    }
    return token[0];
}


Focus On Function:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
string get_iface_name (string pcie_slot)
{
    string cmd = "systool -c net";
    string string_body = GetStdoutFromCommand(cmd);      //grab the output of the above bash command to use as a search_body
    cout << string_body << "\n" << endl;                 //confirm that output to user by printing it to console
    string delim = " ";                             //variable setting the delimiter for the search
    cout << "delim = " << delim << endl;            //confirm that setting to user by printing it to console
    string slotPCIe = "0000:0e:00.0";               //variable setting the id for the expresscard
    cout << "slotPCIe = " << slotPCIe << endl;      //confirm that setting to user by printing it to console
    string deviceTYPE = "0280:";                    //variable setting the id for the device type
    cout << "deviceTYPE = " << deviceTYPE << endl;  //confirm that setting to user by printing it to console
    string DWA_643 = "168c:0024";                   //variable setting the id for the D-Link DWA_643
    cout << "DWA_643 = " << DWA_643 << endl;        //confirm that setting to user by printing it to console
    int i = 150, t=0, c=0;
    string token[i];                                //array to store the slices of the string_body

    auto start = 0U;                                //I don't really understand this line
    auto end = string_body.find(delim);             //I don't really understand this line

    while (end != std::string::npos)                //This while loop scans through the string body
    {                                               //and slices out each substring between the delimiter
            token[t] = string_body.substr(start, end - start);
            cout << token[t];
            start = end + delim.length();
            end = string_body.find(delim, start);
            t++;
            c++;
    }
    return token[0];
}


So my issue is that only following are filled into the array:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Class = "net"

Class Device = "enp0s25"
Device = "0000:00:19.0"

Class Device = "enx001de11bc5eb"
Device = "2-5:1.0"

Class Device = "lo"

Class Device = "wlp12s0"
Device = "0000:0c:00.0"

Class Device = "wls1"
Device = 


Instead of my expected:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Class = "net"

Class Device = "enp0s25"
Device = "0000:00:19.0"

Class Device = "enx001de11bc5eb"
Device = "2-5:1.0"

Class Device = "lo"

Class Device = "wlp12s0"
Device = "0000:0c:00.0"

Class Device = "wls1"
Device = "0000:0e:00.0"


I would really like to keep "0000:0e:00.0" in the string_body. so that when I cut it up again, so that eventually I can have the device address and the interface name in a 2 dimensional array.

Any suggestions into how I should write the code?

Thanks!
So have you started to learn any debugging skills yet?

Once you're past the student homework stage, then most of the time, the code you write won't work first time.

And the way you start to fix it is by using a debugger.
Use the -g flag when you compile, and the debugger will have lots of useful info to help you.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
$ g++ -std=c++11 -g foo.cpp
$ gdb -q ./a.out
Reading symbols from ./a.out...done.
(gdb) b GetStdoutFromCommand
Breakpoint 1 at 0x40126a: file foo.cpp, line 21.
(gdb) b 34
Breakpoint 2 at 0x40133e: file foo.cpp, line 34.
(gdb) run
Starting program: /home/sc/Documents/a.out 

Breakpoint 1, GetStdoutFromCommand (cmd="systool -c net") at foo.cpp:21
21	{                                                           //don't really understand it yet
(gdb) bt
#0  GetStdoutFromCommand (cmd="systool -c net") at foo.cpp:21
#1  0x0000000000401424 in get_iface_name (pcie_slot="0000:0e:00.0") at foo.cpp:39
#2  0x00000000004011bd in main () at foo.cpp:16
(gdb) c
Continuing.

Breakpoint 2, GetStdoutFromCommand (cmd="systool -c net 2>&1") at foo.cpp:34
34	    return data;
(gdb) p data
$1 = "Class = \"net\"\n\n  Class Device = \"eth0\"\n    Device = \"0000:02:00.0\"\n\n  Class Device = \"lo\"\n\n\n"
(gdb) 

You basically step/next/print/breakpoint your way through the code until you discover a point where expectation != reality.

At which point, you stop and think - and you try to decide whether the code is wrong (but your idea is right), or your whole idea itself is wrong (and you need new code).
Your loop only catches tokens that END with a space. So what happens if string_body doesn't end in a space?

Here is a simplified version of your code that demonstrates what I mean.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#include <iostream>
#include <string>

using namespace std;

int main()
{
    string string_body = "This is a test";
    string delim = " ";
    string token[150];
    int t=0, c=0;
    auto start = 0U;		// create a variable named "start"
				// whose type and value are the same
				// as 0U.  0U is an unsigned integer
				// with value zero.

    // Search string_body for the first occurenace of "delim" and
    // return the position.  This gets assigned to a variable called
    // "end" whose type is the same as whatever string::find()
    // returns.  string::find returns the special value string::npos
    // if it can't find the value.
    auto end = string_body.find(delim);
    
    while (end != std::string::npos)                //This while loop scans through the string body
    {                                               //and slices out each substring between the delimiter
            token[t] = string_body.substr(start, end - start);
            cout << token[t];
            start = end + delim.length();
            end = string_body.find(delim, start);
            t++;
            c++;
    }

    cout << "\nExiting the loop because I didn't find a space.\n";
    cout << "What's left ofstring_body is \"" << string_body.substr(start) << "\"\n";
}

Thisisa
Exiting the loop because I didn't find a space.
What's left ofstring_body is "test"

@dhayden: okay so you're saying that at the end of the loop I just need to run string_body.substr(start). Then I can populate that back into the array. so I need to test if npos the measure c and somehow work those into a check that if true populates the final token of the array with string_body.substr(start).

Unless you guys know a cleaner way to snip out the words of string into an array?
This is a job for strtok(). Does anyone know if there's something equivalently convenient in the standard library?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
#include <iostream>
#include <string>
#include <cstring>

using namespace std;

// You might find strdup() already implemented in your library. Check
// <string.h>
char *strdup(const char *cp)
{
    char *result = NULL;
    if (cp) {
	size_t len = strlen(cp);
	result = (char *)malloc(len+1);
	if (result) {
	    memcpy(result, cp, len+1);
	}
    }
    return result;
}

int main()
{
    string string_body = "This is a test";
    const char *delim = " ";
    string token[150];
    unsigned t=0;

    char *str = strdup(string_body.c_str());
    // Use strtok_r instead of strtok() if it's available, just
    // because it's a good habit to write thread-safe code.
    for (char *cp = strtok(str, delim); cp; cp = strtok(NULL, delim)) {
	token[t++] = cp;
    }
    free(str);

    // Print the tokens
    for (unsigned i=0; i<t; ++i) {
	cout << token[i] << '\n';
    }
}

This is a job for strtok(). Does anyone know if there's something equivalently convenient in the standard library?

I think a stringstream using getline with the delimiter be more or less this functionality?
Topic archived. No new replies allowed.