strtok twice a char* [duplicate] - c

I am trying to use strtok() in nested loops but this is not giving me desired results,
possibly because they are using the same memory location. My code is of the form:-
char *token1 = strtok(Str1, "%");
while (token1 != NULL)
{
char *token2 = strtok(Str2, "%");
while (token2 != NULL)
{
//Do something
token2 = strtok(NULL, "%");
}
// Do something more
token1 = strtok(NULL, "%");
}

Yes, strtok(), indeed, uses some static memory to save its context between invocations. Use a reentrant version of strtok(), strtok_r() instead, or strtok_s() if you are using VS (identical to strtok_r()).
It has an additional context argument, and you can use different contexts in different loops.
char *tok, *saved;
for (tok = strtok_r(str, "%", &saved); tok; tok = strtok_r(NULL, "%", &saved))
{
/* Do something with "tok" */
}

strtok is using a static buffer.
In your case you should use strtok_r. This function is using a buffer provided by the user.

WayneAKing posted an alternative in the Microsoft Developer Center.
Citing him:
Go here
http://cpp.snippets.org/code/
and download this file
stptok.c Improved tokenizing
function
You can also download the needed
header files from the same site.
This is a modified version of strtok
which places the parsed tokens
(substrings) in a separate buffer. You
should be able to modify it to
accommodate your needs.
Wayne
P.S. - Note that these files may be in
*nix format with respect to end-of-lines. i.e. - 0x0A only and not
0x0D 0x0A
This is an alternative if you don't have the Microsoft libraries in your environment.

Related

Regular expressions with scanf in C

I'm trying to achieve the following without any success:
Removing the opening
message "
and trailing
"
while leaving the content in between, and saving it into my variable, using sscanf regular expressions.
I wrote the following code:
sscanf( buffer, "message \"%[^\"]", message)
Which works good when I have something like message "Hey there", but when I'm trying the following string, I get only the white space between the two quotation marks.
message " """ This is a Test """ "
The result for this should be """ This is a Test """
Is there a way to upgrade my expression so it will include this extreme event of message? I tried to look it up both in google and here, and couldn't find an elegant answer. I'm aware that it's possible using string manipulation with a lot lines of code, but I'm trying something more simple here.
P.S. The trailing " is the end of the expression, and is a must by the program, after that comes nothing.
Thanks in advance for the feedback!
If you're fine with not using regex for the whole thing:
Original version:
sscanf(buffer, "message \"%[^$]", message); // remove 'message "'
message[strlen(message) - 1] = '\0'; // remove trailing '"'
Safe, correct, and generic version:
char* buffer = ...;
const char* prefix = "message \"";
const char* suffix = "\"";
if (strstr(buffer, prefix) != buffer) {
// error, doesn't start with `prefix`
}
buffer += strlen(prefix);
char* suffixStart = strrchr(buffer, suffix[0]);
if (!suffixStart || strcmp(suffixStart, suffix) != 0) {
// error, doesn't end with `suffix`
}
*suffixStart = '\0'; // strip `suffix`

Breaking a string in C with multiple spaces

Ok, so my code currently splits a single string like this: "hello world" into:
hello
world
But when I have multiple spaces in between, before or after within the string, my code doesn't behave. It takes that space and counts it as a word/number to be analyzed. For example, if I put in two spaces in between hello and world my code would produce:
hello
(a space character)
world
The space is actually counted as a word/token.
int counter = 0;
int index = strcur->current_index;
char *string = strcur->myString;
char token_buffer = string[index];
while(strcur->current_index <= strcur->end_index)
{
counter = 0;
token_buffer = string[counter+index];
while(!is_delimiter(token_buffer) && (index+counter)<=strcur->end_index)//delimiters are: '\0','\n','\r',' '
{
counter++;
token_buffer = string[index+counter];
}
char *output_token = malloc(counter+1);
strncpy(output_token,string+index,counter);
printf("%s \n", output_token);
TKProcessing(output_token);
//update information
counter++;
strcur->current_index += counter;
index += counter;
}
I can see the problem area in my loop, but I'm a bit stumped as to how to fix this. Any help would be must appreciated.
From a coding stand point, if you wanted to know how to do this without a library as an exercise, what's happening is your loop breaks after you run into the first delimeter. Then when you loop to the second delimeter, you don't enter the second while loop and print a new line again. You can put
//update information
while(is_delimiter(token_buffer) && (index+counter)<=strcur->end_index)
{
counter++;
token_buffer = string[index+counter];
}
Use the standard C library function strtok().
Rather than redevelop such a standard function.
Here's the related related manual page.
Can use as following in your case:
#include <string.h>
char *token;
token = strtok (string, " \r\n");
// do something with your first token
while (token != NULL)
{
// do something with subsequents tokens
token = strtok (NULL, " \r\n");
}
As you can observe, each subsequent call to strtok using the same arguments will send you back a char* adressing to the next token.
In the case you're working on a threaded program, you might use strtok_r() C function.
First call to it should be the same as strtok(), but subsequent calls are done passing NULL as the first argument. :
#include <string.h>
char *token;
char *saveptr;
token = strtok_r(string, " \r\n", &saveptr)
// do something with your first token
while (token != NULL)
{
// do something with subsequents tokens
token = strtok_r(NULL, " \r\n", &saveptr)
}
Just put the process token logic into aif(counter > 0){...}, which makes malloc happen only when there was a real token. like this
if(counter > 0){ // it means has a real word, not delimeters
char *output_token = malloc(counter+1);
strncpy(output_token,string+index,counter);
printf("%s \n", output_token);
TKProcessing(output_token);
}

Strtok + If Statement

im new in here and im having a headache with my program,the thing is that i need to get a input from the keyboard and then separate it using strtok but have to separate the tokens using 4 diferent cases and in each case i need to print the result and save it to a string like this:
input String : Label Instruction #50,Y; Label <with>
and the output should look like this:
Label: Label
Instruction: Instruction
Character [1]: #50
Character [2]: Y
Comentaries: Label <with>
also it has to be able to reconize if a instruction is missed like this:
Input String: adda
Output String
Label: -----
Instruction: adda
Character 1: -----
Comentaries: -----
My code can accept the first and correct instruction but when i type a incorrect one like in the second input it ignores it and continue like the first atempt just ading sometimes,i have tryed to use if to be able to separate each token with its delimeter but everitime i compile it it ignores the if statement no matter what argument i gave it i dont know what else to do
Heres my code
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include <ctype.h>
int main() { char word[256];
fgets(word,256,stdin);
char *token;
while (token != NULL){
char delimiter[]="\n , ;";
token=strtok (word,delimiter);
//if(token != "\n") //{
//char delimiter[]="\n , ;";
//token=strtok (word,delimiter);
//if (delimiter != " "||"\t" || "_")
printf("Label \"%s\"\n", token);
token = strtok (NULL, "\n , ;"); //(NULL, "_,.-")//}
//token=strtok (word,delimiter); //}
//printf("Label ----------\n");
if (delimiter != "\n"||"\t")//{
printf("Instruction \"%s\"\n", token);
token = strtok (NULL, "\n , ;"); //(NULL, "_,.-")//}
printf("Character \"%s\"\n", token);
token = strtok (NULL, "\n , ;"); //(NULL, "_,.-")
printf("Character 2 \"%s\"\n", token);
token = strtok (NULL, "\n , ;"); //(NULL, "_,.-")
printf("Comentaries \"%s\"\n",token);
token = strtok (NULL, ";");
// printf("Character 2\"%s\"\n", token);
// token = strtok (NULL, "\n , ;"); //(NULL, "_,.-")
token = NULL;}
//token = NULL;
//printf("Comentaries \"%s\"\n", token);
//token = NULL;
return(0);
}
the // coments are all my failed attempts to try to make it work =(
Can someone help me please?
char *token;
while (token != NULL){
where is token initialized?
Then:
if (delimiter != "\n"||"\t")
You are only comparing pointers in the if controlling expression: use strcmp function to compare strings.
I could see various problems with your code, as listed below:
1.Your while loop is based on token which is not initialized. Better use a do/while.
2.delimiter is a string and cannot be compared using != operator. Use strcmp/strncmp.
3.What is the point of checking delimiter in every iteration when it is the assigned the same value everytime? I am not sure what are you trying to achieve by doing that. AFAIK, the value of delimiter is not changed on a call to strtok.
4.token should pass through a NULL check before every call to strtok as you area allowed to enter a "wrong" string.
5.Nothing wrong with it, but why exactly was fgets used for taking input from stdin, when you could simply do a scanf?
Hope above solves your issues.

Parse SIP packet in C

I am trying to parse a SIP packet and get some information out of it. To be more specific, the packet looks like this
REGISTER sip:open-ims.test SIP/2.0
Via: SIP/2.0/UDP 192.168.1.64:5060;rport;branch=z9hG4bK1489975971
From: <sip:alice#open-ims.test>;tag=1627897650
To: <sip:alice#open-ims.test>
Call-ID: 1097412971
CSeq: 1 REGISTER
Contact: <sip:alice#192.168.1.64:5060;line=5fc3b39f127158d>;+sip.instance="<urn:uuid:46f525fe-3f60-11e0-bec1-d965d1488cfa>"
Authorization: Digest username="alice#open-ims.test", realm="open-ims.test", nonce=" ", uri="sip:open-ims.test", response=" "
Max-Forwards: 70
User-Agent: UCT IMS Client
Expires: 600000
Supported: path
Supported: gruu
Content-Length: 0
Now, from that packet I need to extract the following :
The value after "From: " ( in this case <sip:alice#open-ims.test> )
The value after "Contact: " ( in this case <sip:alice#192.168.1.64 )
The value after "username" ( in this case alice#open-ims.test )
My code so far is this
char * tch;
char * saved;
tch = strtok (payload,"<>;");
while (tch != NULL)
{
int savenext = 0;
if (!strcmp(tch, "From: "))
{
savenext = 1;
}
tch = strtok (NULL, "<>;");
if (savenext == 1)
{
saved = tch;
}
}
printf ("### SIP Contact: %s ###\n", saved);
}
}
Where payload contains the packet as described above.
However, when I run my program, it will result in a segmentation fault. The weird thing is that if I use in strtok the characters "<>;: " and in strcmp the value "sip" the message will parse successfully and it will keep the saved value. But I need to parse all three of the upper values.
Would a sip library help me more with my problem ?
Thanks in advance
I think something like this could work
char * tch;
char * saved;
tch = strtok (payload,"<>;\n\"");
while (tch != NULL)
{
int savenext = 0;
if (strncmp(tch, "From",4)==0)
{
tch = strtok (NULL, "<>;\n\"");
saved = tch;
printf (" SIP From: %s \n", saved);
}
else if (strncmp(tch, "Contact",7)==0)
{
tch = strtok (NULL, "<>;\n\"");
saved = tch;
printf (" SIP Cont: %s \n", saved);
}
if (strncmp(tch, "Authorization",13)==0)
{
tch = strtok (NULL, "<>;\n\"");
saved = tch;
printf (" SIP User: %s \n", saved);
Echoing the comment provided by Rup, I too would recommend using a library as all the heavy lifting has been done for you and you can spend more time focusing on what you are attempting to accomplish with the parsed information.
The GNU oSIP library may be a good place to start.
From the online documentation:
SIP parser:
==========
The initial feature implemented in
osip is a SIP parser. There is not
much to say about it: it is capable of
parsing and reformating SIP requests
and answers.
The details of the parsing tools
available are listed below:
1 SIP request/answer
2 SIP uri
3 specific headers
4 Via
5 CSeq
6 Call-ID
7 To, From, Route, Record-Route...
8 Authentication related headers
9 Content related headers
10 Accept related headers
11 ...
12 Generic header
13 Attachement parser (should support mime)
14 SDP parser
Use a parser if you possibly can. SIP syntax has a grammar so complex that many ABNF parsers can't handle the RFC 3261 ABNF. If you're still thinking writing it yourself is a good idea, you should get familiar with RFC 4475, the SIP torture tests because you should use them if this is going to interact with other systems, and because it will show you why it's so hard to get right.
Read each line and search for each of your substrings ('From:', 'Contact:', 'username') using strstr().
When you encounter a line that contains one of your keywords, split it with strtok() and extract the piece you need accordingly.
I don't know if you need a full-blown SIP lib for extracting these three things, but if you might need to parse more of the packet in the future, it might not be a bad idea.
For strtok use with "<>;", I'd expect your packet to be split into something like the following (newlines removed)
REGISTER sip:open-ims.test SIP/2.0Via: SIP/2.0/UDP 192.168.1.64:5060
rport
branch=z9hG4bK1489975971From:
sip:alice#open-ims.test
None of these will match
if (!strcmp(tch, "From: "))
You'd either need to modify your parser or search through the string returned by strtok for "From: ".
strtok doesn't have to use the same set of delimiters every time. You can use a colon when you are expecting a field label and leave it off when you are expecting the right hand side.

Creating a terminal menu with a challenge

What I wont to do is to create a terminal menu that takes various types of arguments and place it in a array param. Under is the code: Here is some trouble that I have and cant find a good solution for.
if i just type 'list' I will get Not a valid command, I have to type “list “ (list and space).
Menu choice new should be like this: new “My name is hello”. param[0] = new and param[1] = My name is hello , (sow I can create a message with spaces).
How can I accomplish this?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
int menu()
{
printf(">");
char line[LINE_MAX];
int i = 0;
char *param[4];
while(fgets(line, LINE_MAX, stdin) != NULL) {
param[i++] = strtok(line, " \n");
if(param[0] != NULL) {
char *argument;
while((argument = strtok(NULL, "\n")) != NULL) {
param[i++] = argument;
}
}
if(strcmp(param[0], "new") == 0) {
//new(param[1]);
menu();
} else if(strcmp(param[0], "list") == 0) {
//list();
menu();
} else {
printf("Not a valid command.\n\n");
menu();
}
}
return 0;
}
You're delimiting on " ".
fgets reads the ENTER.
So, when you type "listENTER" and tokenise at spaces you get one token, namely "listENTER". Later you compare with "list" and, of course, it doesn't match.
Try
strtok(line, " \n"); /* maybe include tabs too? */
PS. Why are you calling menu recursively? You already have a while in the function ...
Your problem is param[i++] = strtok(line, " "); will only split on space, not on \n (newline). Try adding this to your array of delimeters.
Oh, and congratulations for some decent looking code that's clean and well formatted. A pleasant change.
I'm not sure if this causes your problem but these lines
/*new(param[1]);
/*list();
Start a comment that is never terminated.
If you want one line comments you can use:
// comment
(atleast in C++ and from C99 on)
But comments starting with /*must be ended with a */and not nested:
/* comment */
/* also multi line
allowed */
Since you start a comment in a comment your compiler should have emmited a warning, actually this shouldn't compile at all.
The reason you need to type "list " is that your first strtok tokenizes until a space character, so you need to enter one in this case. Try allowing both '\n' and space as separators, i.e. replace the second parameter of strtok with " \n".
As for quotes, you need to re-combine parameters starting from the one beginning with a quote to the one ending with one by replacing the characters in between them with spaces. Or do away with strtok and parse by manually iterating through the characters in line.

Resources