As I commented on deltaray's answer, a regular expression library is
overkill for finding a fixed string. There is a standard avr-libc
function for that called strstr():
char * strstr(const char *haystack, const char *needle);
where haystack
is the Web page and needle
is the fixed string you
are searching for.
There is an issue with this function though: in order to use it, you
need to have the whole haystack in RAM. For a non-trivial Web page, this
may not be doable on a small Arduino.
Below is a custom solution based on a finite state machine: the
parser can be in a number of different states:
- state 0 = waiting for the 'S' of "Small Craft"
- state 1 = waiting for the 'm' of "Small Craft"
- etc...
The state is actually an index in a character array representing the
string we are looking for. Each time the parser finds the expected
character, it moves to the next state. Otherwise it moves back to state
0. There is a small kludge though: when in the state waiting for the
'N' of "Nil", if it doesn't get an 'N', it moves to the state waiting
for the 'I' of "In Operation" and tries the match again. This way it
can look for both the possible strings at once. Also, once it got the
full preamble "Small Craft Warning: </b>", if it gets something
invalid, it moves to an extra state called INVALID instead of state 0.
Here is the code:
// Possible return values of parse_forecast().
// The last three are sticky.
enum parse_state {
NO_PREAMBLE, // no complete preamble seen yet
PREAMBLE_COMPLETE, // preamble just completed
PARTIAL_NIL, // received preamble and start of "Nil"
PARTIAL_IN_OP, // received preamble and start of "In Operation"
COMPLETE_NIL, // result = Nil
COMPLETE_IN_OP, // result = In Operation
INVALID // valid preamble followed by invalid data
};
parse_state parse_forecast(char c)
{
// position: 0 25 29 42
const char T[] = "Small Craft Warning: </b>Nil\0In Operation\0";
static size_t i; // T[i] is the character we expect next
if (T[i]) { // non-sticky state
if (i == 25 && c != T[i])
i = 29; // switch to "In Op" branch
if (c == T[i]) // found expected char
i++; // wait for the next one
else {
if (i < 25)
i = 0; // reset to start of the string
else
i = 42; // invalid state
}
}
return i < 25 ? NO_PREAMBLE :
i == 25 ? PREAMBLE_COMPLETE :
i < 28 ? PARTIAL_NIL :
i == 28 ? COMPLETE_NIL :
i < 41 ? PARTIAL_IN_OP :
i == 41 ? COMPLETE_IN_OP :
INVALID;
}
With this you do not need to store the Web page in RAM. Instead, you
feed the parser one character at a time and, at the end, check the
return value. You expect it to be either COMPLETE_NIL
or
COMPLETE_IN_OP
.
Implementation detail: there are three NUL characters in the template
string, at positions 28, 41 and 42 (the last one is implicit). They
correspond to the three possible "sticky" states.