I am working on a C code which executes the SCAN and SCAN_RESULTS command via wpa_cli and gets the wifi scan results. I have a problem in parsing the SCAN_RESULTS output to capture the key management and SSID fields under certain scenarios
The code I use to read all parameters is
sscanf(buf, "%s \t %s \t %s \t %s \t %[^\n]s", bssid, freq, siglevel, keymgmt, ssid);
The output of wpa_cli SCAN_RESULTS command will be
bssid / frequency / signal level / flags / ssid
00:00:00:00:00:00 2462 -49 [WPA2-PSK-CCMP][ESS] MYSSID
11:11:11:11:11:11 2437 -64 [WPA2-PSK-CCMP][ESS] ANOTHERSSID
Where the fields are separated by tabs(\t), with the above output my code works fine. But when my scan result have some open network then my code breaks and I have no idea how to change the code to suit my requirement
The output of wpa_cli SCAN_RESULTS command with open network
bssid / frequency / signal level / flags / ssid
00:00:00:00:00:00 2462 -49 [WPA2-PSK-CCMP][ESS] MYSSID
22:22:22:22:22:22 2437 -72 OPENSSID
with the above output my code reports the keymgmt variable holding "OPENSSID" and ssid variable is empty. But I want to have the keymgmt variable as empty and ssid to hold "OPENSSID". When I tried to capture the above output to file and tried hexdump I could see between the "signal level" and "ssid" there is two consecutive tabs(\t\t) present. Any pointers on how to change the sscanf code to make it work
sscanf()
format not working as expected.
IMHO there is no single sscanf()
with a format that will fill a destination string with ""
(or skip it) and then fill a subsequent destination string with text. Once scanf()
finds nothing to put in a destination string, scanning stops.
Alternative code is presented.
int ScanTabbedData(const char *s, char *data[], size_t n) {
size_t i = 0;
const char *Start = s;
while (1) {
if ((*s == '\t') || (*s == '\0')) {
if (i >= n) {
return -1; // More than n data
}
size_t Length = s - Start;
memcpy(data[i], Start, Length);
data[i][Length] = '\0';
i++;
if (*s == '\0') {
return i;
}
s++;
Start = s;
}
else s++;
}
return 0;
}
int main() {
char *str1= "Test\tHope\tHello";
char *str2 = "Test\t\tHello";
char *t[3];
t[0] = malloc(100); t[1] = malloc(100); t[2] = malloc(100);
int n;
n = ScanTabbedData(str1, t, 3);
printf("%d:%s:%s:%s\n", n,t[0], t[1], t[2]);
n = ScanTabbedData(str2, t, 3);
printf("%d:%s:%s:%s\n", n,t[0], t[1], t[2]);
}
2nd Alternative, use strtok()
. I'm not sure it handles a lead/consecutive \t
as OP may want though.
Below is my original answer, which does not meet OP's need.
** Original answer **
First, the result of any sscanf()
should be assessed as in
if (3 != sscanf(buf, "%s\t%s\t%[^\n]s", a, b, c)) handle_error();
If, as the OP suggest, the fields are truly \t
separated, use
if (3 != sscanf(buf, "%[^\t]%*1[\t]%[^\t]%*1[\t]%[^\n]", a, d, c)) handle_error();
"%[^\t]"
scan until a tab is found.
"%*1[\t]"
scan 1 tab, do not save nor add to sscanf() result.
"%[^\n]"
scan until an end-of-line is found.
Note:
3 rather than OP's 5 parameters used for simplicity.
In sscanf()
, " \t "
does the same thing as " "
.
In "%[^\n]s
, certainly the s
is not needed.