1

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:user2@server2.com SIP/2.0
Via: SIP/2.0/UDP pc33.server1.com;branch=z9hG4bK776asdhds Max-Forwards: 70 
To: user2 <sip:user2@server2.com>
From: user1 <sip:user1@server1.com>;tag=1928301774
Call-ID: a84b4c76e66710@pc33.server1.com 
CSeq: 314159 INVITE 
Contact: <sip:user1@pc33.server1.com>
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.

dbush
  • 205,898
  • 23
  • 218
  • 273
btald1331
  • 537
  • 3
  • 8
  • 23
  • 1
    take a look at the `strtok` function – Cecilio Pardo Jan 29 '16 at 13:31
  • Thanks for the suggestion, unfortunately I've already looked into this function. From my understanding it is not thread safe, which is a requirement for me. – btald1331 Jan 29 '16 at 13:32
  • 1
    One issue I found and did not realize, is I was testing this function by passing a command line argument with a \n. But the way I was passing the testing string took the \n literally and not as a new line character – btald1331 Jan 29 '16 at 13:34
  • You cannot use `strcat` to append null termination, because it requires string to be null terminated before use. – user694733 Jan 29 '16 at 13:37
  • 1
    http://stackoverflow.com/questions/4031075/strtok-function-thread-safety... this page suggests using strtok_r for thread safety – CIsForCookies Jan 29 '16 at 13:37
  • 1
    Also, *"this does not work"* is not valid problem description. **Always** provide input, and both expected and actual output, along with any possible error messages. – user694733 Jan 29 '16 at 13:42
  • 2
    http://stackoverflow.com/questions/20299987/loop-through-char-array-line-by-line – BLUEPIXY Jan 29 '16 at 13:45
  • I updated the question to better reflect and show what I am looking for. Thanks for all the help. – btald1331 Jan 29 '16 at 13:51
  • 1
    The code has type errors, tmp is char variable so str+tmp pointer arithmetic is meaningless. Similarly, '\0' is a char, NOT a char * NULL terminated string that can be appended by strcat. To NULL terminate assign '\0' to the end of the data copied. So copy length terminated by '\n', then append '\0'! – Rob11311 Jan 29 '16 at 13:53
  • [https://stackoverflow.com/questions/17983005/c-how-to-read-a-string-line-by-line](https://stackoverflow.com/questions/17983005/c-how-to-read-a-string-line-by-line) – Accountant م Apr 02 '19 at 22:50

3 Answers3

1

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.

dbush
  • 205,898
  • 23
  • 218
  • 273
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?

Basile Starynkevitch
  • 223,805
  • 18
  • 296
  • 547
0

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 );
}
user3629249
  • 16,402
  • 1
  • 16
  • 17