dealing with url

Im parsing url into the variable and saving values specified in keywords.

url string is dynamic which will change depending in this case how many cages are present.

i.e.
char a=“http://192.168.4.1/m17?m0n=dogs&m0t=10&m1n=cats&m1t=5&m2n=tigers&m2t=6&m3n=cougars&m3t=80&m4n=cows&m4t=87&key=222 H”;

in this example 4 cages are present.

now if 1 cage is present I`m getting this type of url.

m0n=dogs&m0t=10&key=222 H

which means value of m0n lies between m0n and &m0t
value of m0t between m0t and &key

now 2 cages are present
m0n=dogs&m0t=10&m1n=cats&m1t=5&key=222 H

now value of m0t lies between m0t and &m1n

and same problem with m2t m3t etc

even though my code that I wrote solves the task but looks very ugly and has redundant approach to solve the problem.

tried to post with code tags but got hit with char limitation so code is in attached file.

sketch_sep29a.ino (9.72 KB)

surepic:
m0n=dogs&m0t=10&key=222 H

which means value of m0n lies between m0n and &m0t
value of m0t between m0t and &key

now 2 cages are present
m0n=dogs&m0t=10&m1n=cats&m1t=5&key=222 H

now value of m0t lies between m0t and &m1n

and same problem with m2t m3t etc

Not a problem.
The names always lie between ‘&’ and ‘=’.
Value assigned to the name always lies between ‘=’ and &’ or ‘\r’ or ‘\n’

Since all of your values are digits, just gather digits until you find a non-digit.

Small update:
Names i.e dogs,cats etc are as user dependant as qty values which must be numbers and are checked for that rule.

I do not really see a question in your post. Are you asking for advise how to improve?

Exactly

You can start by combining related information in a struct or class; I’m more a C programmer than a C++ programmer so will show an approach with a struct.

A struct is like an entry in a phone book where it combines a name with a phone number and possibly an address.

struct CAGE
{
  char name[11];
  char qty[3];
};

// 5 cages
CAGE cages[5];

// url to parse
char url[] = "http://192.168.4.1/m17?m0n=dogs&m0t=10&m1n=cats&m1t=5&m2n=tigers&m2t=6&m3n=cougars&m3t=80&m4n=cows&m4t=87&key=222 H";

void setup()
{
  Serial.begin(57600);

  // clear the array; this is not necessary in this case as it's a global variable that is in itialised to 0
  // memset(cages, 0, sizeof(cages));
  
  ...
  ...
}

void loop()
{
}

Next you can parse the url; the first step is to look for the ‘?’. The below uses strchr().

void setup()
{
  ...
  ...
  // find the '?'
  char *data = strchr(url, '?');
  // if not found
  if (data == NULL)
  {
    Serial.println("no data");
    for (;;);
  }
  // data is after '?'
  data++;

  Serial.print("data = "); Serial.println(data);
  ...
  ...

Now you can split the data on ‘&’; this will give you key/value pairs. Below uses strtok() which is destructive; that means that the original url will be corrupted.

  // temporary variables
  char key[11];
  char value[3];

  char *ptr;
  ptr = strtok(data, "&");

  while (ptr != NULL)
  {
    Serial.println(ptr);
    ptr = strtok(NULL, "&");
  }
}

The output below

data = m0n=dogs&m0t=10&m1n=cats&m1t=5&m2n=tigers&m2t=6&m3n=cougars&m3t=80&m4n=cows&m4t=87&key=222 H
m0n=dogs
m0t=10
m1n=cats
m1t=5
m2n=tigers
m2t=6
m3n=cougars
m3t=80
m4n=cows
m4t=87
key=222 H

Now you can split a key/value pair; I used a function for that that can be called from the while-loop.

/*
  parse key/value pair
  In:
    key/value pair
  Out:
    key
    value
  Returns:
    true on success, else false
*/
bool parseKvp(char *kvp, char *key, char *value)
{
  char *ptr;
  // find the =
  ptr = strchr(kvp, '=');
  // if not found
  if (ptr == NULL)
  {
    return false;
  }
  // replace '=' by '\0' (nul terminator
  *ptr = '\0';
  // copy key and value
  strcpy(key, kvp);
  strcpy(value, ptr + 1);
  // restore '='; depends on need if this is needed
  *ptr = '=';
  // indicate ok
  return true;
}

This simply finds the first ‘=’. What is before that is the key, after that is the value. Note that the code initially corrupts the ‘=’ and later restores it so this approach is non-destructive (contrary to strtok()).

Now you can use it in the while-loop

  while (ptr != NULL)
  {
    Serial.println(ptr);
    // parse the key/value pair and get a key and a value back
    bool rv = parseKvp(ptr, key, value);
    if (rv == false)
    {
      Serial.println("No '=' found in key/value pair");
    }
    else
    {
      Serial.print("\tkey = "); Serial.println(key);
      Serial.print("\tvalue = "); Serial.println(value);

      Serial.print("\tcurrentM = "); Serial.println((char)key[0]);
      Serial.print("\tcurrentN = "); Serial.println((char)key[1]);
      Serial.print("\tcurrentX = "); Serial.println((char)key[2]);

      // if first character is 'm'
      if (key[0] == 'm')
      {
        // if 3rd character indicates name
        if (key[2] == 'n')
        {
          strcpy(cages[key[1] - '0'].name, value);
        }
        // if 3rd character indicates quantity
        else if (key[2] == 't')
        {
          strcpy(cages[key[1] - '0'].qty, value);
        }
        else
        {
          Serial.println("error");
        }
      }
    }
    ptr = strtok(NULL, "&");
  }

The code parses the kvp, checks the key and based on the last character of the key copies the value to one of the fields of the array element indicated by the second character. This will work for up to 10 cages (m0X…m9X).

Complete code below; I’ve added a printing of the array

struct CAGE
{
  char name[11];
  char qty[3];
};

CAGE cages[5];

char url[] = "http://192.168.4.1/m17?m0n=dogs&m0t=10&m1n=cats&m1t=5&m2n=tigers&m2t=6&m3n=cougars&m3t=80&m4n=cows&m4t=87&key=222 H";

void setup()
{
  Serial.begin(57600);

  // clear the array; this is not necessary in this case as it's a global variable that is in itialised to 0
  memset(cages, 0, sizeof(cages));

  // find the '?'
  char *data = strchr(url, '?');
  // if not found
  if (data == NULL)
  {
    Serial.println("no data");
    for (;;);
  }
  // data is after '?'
  data++;

  Serial.print("data = "); Serial.println(data);

  // temporary variables
  char key[11];
  char value[3];

  char *ptr;
  ptr = strtok(data, "&");

  while (ptr != NULL)
  {
    Serial.println(ptr);
    // parse the key/value pair and get a key and a value back
    bool rv = parseKvp(ptr, key, value);
    if (rv == false)
    {
      Serial.println("No '=' found in key/value pair");
    }
    else
    {
      Serial.print("\tkey = "); Serial.println(key);
      Serial.print("\tvalue = "); Serial.println(value);

      Serial.print("\tcurrentM = "); Serial.println((char)key[0]);
      Serial.print("\tcurrentN = "); Serial.println((char)key[1]);
      Serial.print("\tcurrentX = "); Serial.println((char)key[2]);

      // if first character is 'm'
      if (key[0] == 'm')
      {
        // if 3rd character indicates name
        if (key[2] == 'n')
        {
          strcpy(cages[key[1] - '0'].name, value);
        }
        // if 3rd character indicates quantity
        else if (key[2] == 't')
        {
          strcpy(cages[key[1] - '0'].qty, value);
        }
        else
        {
          Serial.println("error");
        }
      }
    }
    ptr = strtok(NULL, "&");
  }

  for (uint8_t cageIndex = 0; cageIndex < sizeof(cages) / sizeof(cages[0]); cageIndex++)
  {
    Serial.print("cage "); Serial.println(cageIndex + 1);
    Serial.print("\tname = "); Serial.println(cages[cageIndex].name);
    Serial.print("\tqty  = "); Serial.println(cages[cageIndex].qty);
  }

}

/*
  parse key/value pair
  In:
    key/value pair
  Out:
    key
    value
  Returns:
    true on success, else false
*/
bool parseKvp(char *kvp, char *key, char *value)
{
  char *ptr;
  // find the =
  ptr = strchr(kvp, '=');
  // if not found
  if (ptr == NULL)
  {
    return false;
  }
  // replace '=' by '\0' (nul terminator
  *ptr = '\0';
  // copy key and value
  strcpy(key, kvp);
  strcpy(value, ptr + 1);
  // restore '='; depends on need if this is needed
  *ptr = '=';
  // indicate ok
  return true;
}

void loop()
{

}

It’s not immediately clear to me what you wanted to do with the key at the end of the url; you should now have enough ammunition to do with it what you need to do.

Note, this is just a demo. The last part prints

cage 1
	name = dogs
	qty  = 10
cage 2
	name = cats
	qty  = 5
cage 3
	name = tigers
	qty  = 6
cage 4
	name = cougars
	qty  = 80
cage 5
	name = cows
	qty  = 87

I hope this gets you on track.

PS
I used strcpy(); you will need to check if the length of the values don’t exceed the elements in the struct.

sterretje: PS I used strcpy(); you will need to check if the length of the values don't exceed the elements in the struct.

Use the function 'strncpy()' instead. It takes a third argument which is the size of the destination buffer. For example:

          strncpy(cages[key[1] - '0'].qty, value, sizeof cages[0].qty );

strncpy does not add a '\0' if it's not in the first N characters of the string to be copied. But that can easily be fixed by overwriting the last byte of the destination.

Thanks a lot for taking time and writing detailed explanation of the method described. Im running out of flash memory hope this will help reduce it a little.

In my code i have to be sure that url that is sent is without errors i.e. in case of someone modifies the string in the browser and sends. Now i think its overkill for uno to check keywords in url like “m0n” “m0t” etc.