How to slice/split a string by delimiter

DKWatson:
String msgField[25];
String fullMsg = "";

Not just String, not just arrays of String, but unsafe array usage. Sigh. If only there were a better way to parse GPS data...

@benskylinegodzilla, here are two ways to watch for the magic ColVal in the incoming stream of bytes. Both sketches use Serial for the client so you can simply paste the HTTP request into the Serial Monitor window and press Send.


Line-oriented processing with C string functions

One line is accumulated at a time. Then the line is searched with strstr for the special match string. If a match is found, it steps over the match string to the value characters and uses atoi to convert the digits into an int.

Once the match string and color value are found, it skips the rest of the request until the two newlines are found.

#define client Serial

void setup()
{
  client.begin( 9600 );
}

const char     match[]       = "GET /HourRed/ColVal="; // watch for this
      uint8_t  redColorValue = 0;



void loop()
{
      if (client.available())
      {
        char c = client.read();
        Serial.write(c); // echo for testing

        if (parseRequest( c )) {
          sendResponse();
        }
      }

}


//  Some variables to receive a line of characters
const size_t   MAX_CHARS          = 64;
      char     line[ MAX_CHARS ];
      size_t   count              = 0;
      bool     previousWasNewline = false;
      bool     colorReceived      = false;

bool parseRequest( char c )
{
  bool isNewline = (c == '\n');

  //  Only pay attention until a color value is received.  Then ignore.
  if (not colorReceived) {

    if (not isNewline) {
      // Only save the printable characters, if there's room
      if ((' ' <= c) and (count < MAX_CHARS-1)) {
        line[ count++ ] = c;
      }

    } else {
      //  The newline is here, line completely received
      line[count] = '\0'; // terminate the string
      count       = 0;    // reset for next time

      // See if it is the special string
      char *found = strstr( line, match );
      if (found != nullptr) {

        //  The value is after the match string.  Start at the
        //     found position and step by the match string length.
        char *colorValuePtr = &found[ sizeof(match)-1 ];

        // Convert the next characters to an int value.
        //    atoi stops at the first non-digit.
        redColorValue = atoi( colorValuePtr );
        colorReceived = true;

        // Do something with the value now?  Look at it later?
        Serial.print( "\nRed Color Value = " );
        Serial.println( redColorValue );
      }
    }
  }

  bool done = (isNewline and previousWasNewline) and colorReceived;

  if (done) {
    // Reset a few things
    colorReceived      = false;
    previousWasNewline = false;
  } else {
    previousWasNewline = isNewline; // remember for next time
  }

  return done;

} // parseRequest

void sendResponse()
{
  // HTTP headers always start with a response code (e.g. HTTP/1.1 200 OK)
  // and a content-type so the client knows what's coming, then a blank line:

  client.println("HTTP/1.1 200 OK\n"
                 "Content-type:text/html\n"
                 "Connection: close\n"); // one print!

  //HTML body Code goes here
  client.println("<!DOCTYPE html>");
  client.println("<html>");

    // This is where all the HTML code is
    // there is one line that says
    client.print("    <a href=\"/HourRed/\" onmouseup=\"location.href=this.href+'ColVal='+sliderHourRed.value;return false;\">");

  client.println( "</html>" );
  //END OF HTML
  // The HTTP response ends with another blank line
  client.println();

}

Finite-State Machine

Instead of accumulating an entire line, it compares each character as it arrives to a "match" string. As the characters continue to match, it increments a counter. When the entire string has matched, it knows to start watching for the color value.

Again, instead of saving the complete color value string, it accumulates the color value as the digits arrive. When a non-digit character arrives, it knows that the value is complete. The rest of the response can be ignored, until two newline characters arrive.

Each character affects the FSM as it arrives. There is no reason to hold on to the entire HTTP request string.

#define client Serial

void setup()
{
  client.begin( 9600 );
}

const char    match[]              = "GET /HourRed/ColVal="; // watch for this
      size_t  count                = 0;
      bool    previousWasNewline   = false;
      uint8_t redColorValue        = 0;

enum parsingState_t { WAITING_FOR_MATCH, GETTING_VALUE, VALUE_READY };
parsingState_t state = WAITING_FOR_MATCH;


void loop()
{
      if (client.available())
      {
        char c = client.read();
        Serial.write(c); // echo for testing

        if (parseRequest( c )) {
          sendResponse();
        }
      }

}


bool parseRequest( char c )
{
  bool isNewline     = (c == '\n');

  switch (state) {

    case WAITING_FOR_MATCH:

      if (c == match[ count ]) {

        count++;
        if (count == sizeof(match)-1) {
          // FOUND the match string
          count         = 0;   // reset for next time
          redColorValue = 0;   // initial value
          state         = GETTING_VALUE;
        }

      } else {
        count = 0; // didn't match, start over
      }
      break;


    case GETTING_VALUE:

      if (isdigit(c)) {
        // Accumulate the red color value
        uint8_t digit = c - '0';
        redColorValue = redColorValue * 10 + digit;

      } else {
        //  It wasn't a digit, so we must have all the
        //     color digits.  The value is ready to use.
        state = VALUE_READY;

        // Do something with the value now?  Look at it later?
        Serial.print( "\nRed Color Value = " );
        Serial.println( redColorValue );
      }
      break;

    case VALUE_READY:
      // Ignore the rest of the request?

      break;
  }

  bool colorReceived;

  if (isNewline and previousWasNewline) {
    // End of request!
    colorReceived      = (state == VALUE_READY);

    // reset FSM for next request
    state              = WAITING_FOR_MATCH; 
    count              = 0;
    previousWasNewline = false;
  } else {
    colorReceived      = false;
    previousWasNewline = isNewline; // remember for next time
  }

  return colorReceived;

} // parseRequest


void sendResponse()
{
  // HTTP headers always start with a response code (e.g. HTTP/1.1 200 OK)
  // and a content-type so the client knows what's coming, then a blank line:

  client.println("HTTP/1.1 200 OK\n"
                 "Content-type:text/html\n"
                 "Connection: close\n"); // one print!

  //HTML body Code goes here
  client.println("<!DOCTYPE html>");
  client.println("<html>");

    // This is where all the HTML code is
    // there is one line that says
    client.print("    <a href=\"/HourRed/\" onmouseup=\"location.href=this.href+'ColVal='+sliderHourRed.value;return false;\">");

  client.println( "</html>" );
  //END OF HTML
  // The HTTP response ends with another blank line
  client.println();

}

In either case, watching for two newline characters is actually a simple FSM. If a non-newline character is received, a flag is cleared. If a newline is received, a flag is set. If the flag was already set, you know that two newlines were received in a row. This flag is a "state" variable.

Cheers,
/dev