简体   繁体   中英

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: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.

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, ie not Windows. For Windows, the equivalent function is strtok_s .

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 (eg 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 ?

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 );
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM