views:

594

answers:

5

I have an application written in C that reads text messages from a modem using AT commands. A typical AT response from the modem looks like this:

+CMGL: 1,"REC READ","+31612123738",,"08/12/22,11:37:52+04"

The code is currently set up to only retrieve the id from this line, which is the first number, and it does so using the following code:

sscanf(line, "+CMGL: %d,", &entry);

Here, "line" is a character array containing a line from the modem, and "entry" is an integer in which the id is stored. I tried extending this code like this:

sscanf(line, "+CMGL: %d,\"%*s\",\"%s\",", &entry, phonenr);

I figured I would use the %*s to scan for the text in the first pair of quotes and skip it, and read the text in the next pair of quotes (the phone number) into the phonenr character array.

This doesn't work (%*s apparently reads "REC" and the next %s doesn't read anything).

An extra challange is that the text isn't restricted to "REC READ", it could in fact be many things, also a text without the space in it.

A: 

You can use strchr() to find the position of '+' in the string, and extract the phone number after it. You may also try to use strtok() to split the string with '"', and analyze the 3rd part.

forcey
There is absolutely no guaranties that the phonenumber will contain a '+' character, so this does not sound like a robust suggestion.
hlovdal
Thanks for the suggestion, but I actually already have cases where there's no + char in telehpone numbers. For example text messages sent from Google Calendar are from "Google", rather than a number, even.
pbean
+1  A: 

Sscanf is not very good for parsing, use strchr rather. Without error handling:

#include <stdio.h>

int main(void)
{

        const char *CGML_text = "+CMGL: 1,\"REC READ\",\"+31612123738\",,\"08/12/22,11:37:52+04\"";
        char *comma, *phone_number_start, *phone_number_end;
        comma = strchr(CGML_text, ',');
        comma = strchr(comma + 1, ',');
        phone_number_start = comma + 2;
        phone_number_end = strchr(phone_number_start, '"') - 1;
        printf("Phone number is '%.*s'\n", phone_number_end + 1 - phone_number_start, phone_number_start);
        return 0;
}

(updated with tested, working code)

hlovdal
Strchr sounds like a good solution which I have considered as well. However, since I am not sure what kind of text is between the first pair of quotes, I also can't predict if it will have a comma, which would screw up this routine. It could be extended to take care of that situation, but then I would have to consider a lot of additional exception cases as well.
pbean
Very good point about possible comma in within strings, however if you look up the <stat> definition to the AT+CMGL command in http://www.3gpp.org/ftp/Specs/html-info/27005.htm you will see that none of the possible values have ("REC UNREAD", "REC READ", "STO UNSENT", "STO SENT", "ALL").
hlovdal
Thanks hlovdal. I had a data sheet of the modem I am using and the even though those values are listed as possible input for the AT+CMGL= command it provided no list of the possible values for the returned +CMGL command.I understand you have some experience in the field though. Would you recommend your own solution, or the one I posted in an answer? :)
pbean
I do seriously recommend against using sscanf for anything. Really. Search for "sscanf crash" and look at all the pages returned. "The GNU C Programming Tutorial" (http://crasseux.com/books/ctutorial/index.html) says: "The sscanf function is just like the deprecated parent scanf function, .... The scanf function is considered dangerous for a number of reasons.". Please do not use it.
hlovdal
Yes, I know a bit about AT commands (I just co-edited a Change Request for 27.007 last week). With regards to parameter parsing I can also add that strings are guaranteed to never contain the " character inside (i.e. " are escaped, but not as \" which is common elsewhere), see chapter "5.4.2.2 String constants" in V.250 (http://www.itu.int/rec/T-REC-V.250-200307-I/en). This means that the safe and correct algorithm for parsing parameters are to split on comma between numeric parameters, and for string parameters you advance by searching for the terminating " character.
hlovdal
A: 

%s in scanf() reads until whitespace.

You're very close to a solution.

To read this;

+CMGL: 1,"REC READ"

You need;

"+CMGL: %d,"%*s %*s"

Blank Xavier
This is one of the first things I considered, but this actually didn't work quite as I expected and couldn't get it to work.
pbean
However this will fail for <stat> value "ALL" which does not contain a space.
hlovdal
+1  A: 

The way I solved it now is with the following code:

sscanf(line, "+CMGL: %d,\"%*[^\"]\",\"%[^\"]", &entry, phonenr);

This would first scan for a number (%d), then for an arbitrary string of characters that are not double quotes (and skip them, because of the asterisk), and for the phone number it does the same.

However, I'm not sure yet how robust this is.

pbean
A: 

Hello, Could you please explain the way you read the messages from the modem? thanks. Regards, Miky.

Miky