-2

I have data which is looking like this:

header:dataA:dataB

I am trying to get the header and the dataA and dataB as separate strings. So I wrote this function which probably is not that good:

#define maxDataSize 50
//.....

char header[20];
char dataA[maxDataSize];   
char dataB[maxDataSize]; 

//**** a call to the function that parse the data
getHeader(BLEcontent,1,header); // here "BLEcontent" has the incoming data
getHeader(BLEcontent,2,dataA);
getHeader(BLEcontent,3,dataB);

//***** call the function that use the data
newDataFromBLE(header,dataA, dataB);

//function that parses the data:
void getHeader( char localString[], int seperatorNum,char *newdata)
{   
    const char seperator=':';  
    int counter=0;
    int divider=0;

    //clear array when it has garbage it added
    for( int i = 0; i < maxDataSize;  ++i )
        newdata[i] = (char)0;

    for(int k=0;k<maxDataSize;k++)
    { 
        if ( localString[k]==  seperator   )
        {  
            counter++;
            divider=k+1;
            if(counter==seperatorNum)
            {   return ;     } 
        }
        if( (seperatorNum-1) ==counter)
            newdata[k-divider]=localString[k];
    }
    return ;   
}

Later when I'm trying to use the function data, stored in header/dataA/dataB:

void newDataFromBLE(char header[],char dataA[], char dataB[])
{
    Serial.println("got:");
    Serial.println(header);
    Serial.println(dataA);
    Serial.println(dataB);
    if (strcmp (header,"setWifi") == 0)
        //... do stuff here

I get here some very strange results. For example, if the incoming data is setWifi:a, I get a good result. If it is abcd:abc I get garbage. And if it is setWifi:a:b, I also get garbage.

It seems that if what I send is not corresponding to the first if statement, it will give me garbage even though it's BEFORE the if. Seems that it knows(??) about the upcoming if..

It used to work before..

TryinHard
  • 4,078
  • 3
  • 28
  • 54
Curnelious
  • 1
  • 16
  • 76
  • 150
  • 2
    Can you use [`strtok`](http://stackoverflow.com/questions/3889992/how-does-strtok-split-the-string-into-tokens-in-c)? –  Jul 13 '15 at 06:54
  • I'm confused by the c-tag in combination with your `Serial.println` lines. –  Jul 13 '15 at 06:55
  • This would be only valid C if there was some global structure `Serial` whith a function pointer `println()`. But yes, my thoughts -- don't reinvent the wheel, use `strtok()`, optionally on a copy of the input string. –  Jul 13 '15 at 06:57
  • sorry,forget about the serial, its just an hardware way to print something, i guess the problem is in my C functions which are not good at all.. – Curnelious Jul 13 '15 at 06:59
  • @Evert i cant use strtok because i am using threads, and i dont want to get into the complications involve with the memory of the strtok .. – Curnelious Jul 13 '15 at 07:05
  • 1
    I guess there's no `strtok_r()` on your platform then? –  Jul 13 '15 at 07:27
  • I am checking it now, thanks for the help. – Curnelious Jul 13 '15 at 07:35
  • 1
    `sscanf(BLEcontent, "%19[^:]:%[^:]:%[^\n]", header, dataA, dataB);` – BLUEPIXY Jul 13 '15 at 07:57

2 Answers2

3

To split your data you can use the char* strtok( char* str, const char* delim ); function. For thread safty use the char *strtok_r(char *str, const char *delim, char **saveptr); function.

See the following Example which uses the strtok_r function:

#include <stdio.h>
#include <string.h>

//#define maxsize 20
int main ()
{
  int i = 0;
  char str[] ="setWifi:dataA:dataB";
  char *delimeter = ":";
  char *saveptr1;
  char *header = strtok_r(str, delimeter, &saveptr1);
  char **dataArr = malloc(5);

  for (i=0; i< 5; i++) {
    dataArr[i] =  strtok_r(NULL, delimeter, &saveptr1);
    if (dataArr[i] == NULL)
        break;
    printf(" %s\n", dataArr[i]);
  }


  if (strcmp(header, "setWifi") == 0) {
    printf("'setWifi' header was set!");
  }
  free(dataArr);

  return 0;
}

Working Example: http://ideone.com/renn2q

Output:

 dataA
 dataB
'setWifi' header was set!

The strtok_r() function is a reentrant version strtok(). The saveptr argument is a pointer to a char * variable that is used internally by strtok_r() in order to maintain context between successive calls that parse the same string.

See: http://linux.die.net/man/3/strtok_r

Zelldon
  • 5,396
  • 3
  • 34
  • 46
  • 2
    I cant use it. thats because strtok has a memory , and i am working with threads here, i prefer not even going into this. – Curnelious Jul 13 '15 at 07:00
  • @Curnelious: I don't get what you are trying to say? – ckruczek Jul 13 '15 at 07:07
  • 2
    strtok has memory. if you use threads in your software, you can get into complicated situations where it has something in the memory stuck and than you are trying to use it with another string. – Curnelious Jul 13 '15 at 07:09
  • Thanks, but you makes things very complicated for me, because when you free the dataArr ?? the place where you do that is another place ,another class, it seems that this way is much more complicated than my simple way. – Curnelious Jul 13 '15 at 07:30
  • See my updated answer @Curnelious you can use the strtok_r function to split your strings. – Zelldon Jul 13 '15 at 07:30
  • Can you show in your answer how you would create one function that gets as an argument the place of the ":" that i need and get back the relevant word- e.g. header/dataA/dataB ? – Curnelious Jul 13 '15 at 07:33
1

You can use strsep. The man page says

The strsep() function was introduced as a replacement for strtok(3), since the latter cannot handle empty fields. It is thread safe.

Using strsep

#include <string.h>
#include <stddef.h>

. . .

const char string[] = "header:dataA:dataB";
const char delimiters[] = ":";
char * running = strdupa(string);
char * token;

. . .

token = strsep(&running, delimiters);    /* token => "header" */
token = strsep(&running, delimiters);    /* token => "dataA" */
token = strsep(&running, delimiters);    /* token => "dataB" */
token = strsep(&running, delimiters);    /* token => NULL */
Shreevardhan
  • 12,233
  • 3
  • 36
  • 50
  • http://www.gnu.org/software/libc/manual/html_node/Finding-Tokens-in-a-String.html One difference between strsep and strtok_r is that if the input string contains more than one character from delimiter in a row strsep returns an empty string for each pair of characters from delimiter. This means that a program normally should test for strsep returning an empty string before processing it. – Zelldon Jul 13 '15 at 08:27
  • @Zelldon Right, this needs checks for non empty `token`. – Shreevardhan Jul 13 '15 at 08:34