Reputation: 159
I am working on a command parser that is supposed to accept a command line terminating with \r\n and extract its parameters
The command line structure is as follows:
all the parameters inside () are mandatory and the arguments inside [] are optional,and spc stands for blank-space or space. and \t stands for tab
AP is and decimal integer between 1...4 RT,WL are a decimal unsigned integer numbers = is equal symbol % is percentage symbol Followings is an acceptable command structure
[spc] MYCMD [spc] (\t) [spc] (AP) [spc] (:) (WL)(=)(RT)spcspc(\n)
As an example follwoing commands sre correct: (The whole command is case insensitive)
MYCMD \t 1 : 540 = 21% \r\n
MYCMD \t 2 : 712= 25 % \r\n
MYCMD\t 3 : 200 =17%\r\n
and ...
Following commands are incorrect:
MYCMD \t 5: 540 = 21% \r\n ---> 5 is not in range 1..4
MYCMD \t 2 : 712 25% \r\n ---> There is no equal symbol
MYCMD 3 200 =17\r\n --->there is no : between 3 and 200, no percentage symbol
MYCMD 3 100 =1 ,,.\n ----> there are extra symbols after 1 and \r does not exist
MYCMD 2: 130 =17.1\r\n ----> the sscanf parser must not translate 17.1 float to integer 7
I have implemented sscanf control format but it does not parse correctly!
int n_parsed=sscanf(cmd_str,"%*sMYCMD[*^\t]%*s%[1234]:%u%*s%[=]%u\r\n",&int_ap,&uint_wl,&uint_rt);
But this does not work for the correct commands (n_parsed never gets 3).
Any hint or comments on fixing the parsing issue will be appreciated Thanks
Upvotes: 0
Views: 1112
Reputation: 153457
Cannot be done solely with sscanf()
.
A key problem is that " "
as well as "\r"
as well as "\n"
in the format string (aside from inside "[ ]"
) will optionally scan any number 0+ white-spaces and OP has very specific requirements. Optional spaces ' '
, but not other white-spaces, is difficult to do in sscanf()
.
Another problem is the %d
et al, consume optionally leading whitespace and we need to prevent that or let it go.
There is a discrepancy between the format and the examples in the location of the "%". I assume the example is correct.
There is a discrepancy between the format and the examples in the end-of-line \r\n
versus \n
. I assume any trailing whitespace before a final \r\n.
There is a discrepancy between the format and the examples in that spaces are allowed before the numbers. I assume spaces are OK.
The more I look at it I see lots of discrepancies between the stated format and the correct examples. I'll go for whatever is easiest to pass the examples in those cases.
int sep[4] = { 0 };
int int_ap;
unsigned uint_wl, uint_rt;
// [spc] MYCMD [spc] (\t) [spc] (AP) [spc] (:) (WL)(RT)(=)spcspc(\n)
const char *format = " MYCMD%n %n%1d :%u =%u%n %n";
int n_parsed = sscanf(cmd_str, format,
&sep[0], &sep[1], &int_ap, &uint_wl, &uint_rt, &sep[2], &sep[3]);
if (sep[3] == 0) DidNotReadEnd();
if ((int_ap < 1) || (int_ap > 4)) RangeError();
unsigned TabCount = 0;
int n;
for (n = sep[0]; n < sep[1]; n++) {
if (cmd_str[n] == '\t') TabCount++;
}
if (TabCount != 1) WrongTabCount;
for (n = sep[2]; n < sep[3]; n++) {
if (cmd_str[n] != ' ') break;
}
if (strcmp(&cmd_str[n], "\r\n") != 0) EOLError();
Note: int_ap could be scanned with %1[1-4]
into a string and than converted to an int
.
I fully expect a claim that this can all be done with only a sscanf()
format. I am confident such and approach can be broken.
Upvotes: 0