btald1331
btald1331

Reputation: 597

Reading a C string line by line

I am trying to parse SIP headers into a line. I do this by iterating over a string line by line. Each header should be separated by a new line character.

The input string will look something similar to this:

INVITE sip:[email protected] SIP/2.0
Via: SIP/2.0/UDP pc33.server1.com;branch=z9hG4bK776asdhds Max-Forwards: 70 
To: user2 <sip:[email protected]>
From: user1 <sip:[email protected]>;tag=1928301774
Call-ID: [email protected] 
CSeq: 314159 INVITE 
Contact: <sip:[email protected]>
Content-Type: application/sdp 
Content-Length: 142

My code:

void readlines(char *str){
  int i;
  int reset;
  char current_line[500];
  char tmp = 0;
  for( i=0; i<strlen(str); i++ ){
      tmp = str[i];
    if (tmp == '\n'){
      strncpy(current_line, str+tmp, i);
      strcat(current_line, '\0');
      printf("current line = %s", current_line);
    }
  }
}

In my code you can see an if block. In the if block I print out the current line as a cheap way to test my solution, the result of this print statement is nothing. Maybe my understanding on how c interprets the \n character is not complete.

Upvotes: 1

Views: 6570

Answers (3)

dbush
dbush

Reputation: 223787

As mentioned in the comments, strtok_r is the ideal function for this. It is used to parse a string based on delimiters, and takes a separate pointer for state so that it's safe in multithreaded programs.

void readlines(char *str){
  char *p, *temp;
  p = strtok_r(str, "\n", &temp);
  do {
      printf("current line = %s", p);
  } while ((p = strtok_r(NULL, "\n", &temp)) != NULL);
}

Note that this function modifies the string it is working on, so make a copy and work on that if need be.

EDIT:

As mentioned in the comments, strtok_r is only available on POSIX systems, i.e. not Windows. For Windows, the equivalent function is strtok_s.

Upvotes: 1

user3629249
user3629249

Reputation: 16540

the posted code contains a few problems.

missing the header files:

#include <stdio.h> // printf()
#include <string.h> // strlen(), strncpy(), strcat()

the strcat() expects both parameters to be char* not an actual character So the call to strcat() should be:

strcat(current_line, "\0");

Now, regarding the execution of the code.

(assume str is a pointer to an array of char that is not NUL terminated and is less than 500 bytes long)

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

void readlines(char *str)
{
    size_t i;
    char *current_line = NULL;

    for( i = 0; i< 500 && '\n' != str[i]; i++);

    if( NULL == (current_line = calloc( i+2, 1 ) ) )
    { // then malloc failed
        perror( "calloc failed" );
        exit( EXIT_FAILURE );
    }

    // implied else, calloc successful

    memcpy( current_line, str, i );
    printf("current line = %s", current_line);
    free( current_line );
}

Upvotes: 0

If you are on POSIX, use its getline function (probably on a FILE* which is your TCP socket, eg. using fdopen; or you could get a FILE* handle from a buffer using fmemopen). If you don't have getline, standard C99 has fgets but you'll either limit the line length to some fixed size buffer length or need to reallocate it.

If you have already all the header data in some buffer, you can parse it using sscanf (handle its return count, use also %n), or parse it manually (e.g. using some strcmp), etc. And of course strtok_r as mentioned by others.

Did you consider using some existing SIP implementation library? Notably GNU oSIP?

Upvotes: 0

Related Questions