How to manipulate string properly in C - c

I'm still new in C. I'm doing an enviroment variable task and I'm having a problem in processing my string. I would like to pass a variable that represent the environment variable, and replace a value that has ${...} with environment value if that string are same as the enviroment key. Here are the codes:
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
void replace_env(char *string, char *env)
{
int y = 0;
int x = 0;
int j = 0;
int i = 0;
int n = 0;
int val_length;
int location2[100];
char *tmp3[BUFSIZ];
char env_key[BUFSIZ];
char env_val[BUFSIZ];
char env_var[sizeof(env)][BUFSIZ];
char user_input[BUFSIZ];
char final_string[BUFSIZ];
char tmp_key[100][BUFSIZ];
tmp3[x]=env;
strncpy(env_var[x],tmp3[x],sizeof(tmp3));
for(x=0;env_var[y][x] != '=';x++) //this is to get the environment key
{
env_key[x] = env_var[y][x];
}
x++;
for(j=0;env_var[y][j] != '\0';j++) //this is to get the environment value
{
env_val[j]=env_var[y][x];
x++;
}
val_length = strlen(env_val);
j=0;
y=0;
strncpy(user_input,string,sizeof(user_input));
for(x = 0;user_input[x] !='\0';x++)
{
if (user_input[x] =='$')
{
x++;
if(user_input[x] == '{')
{
x++;
y=0;
while(user_input[x]!='}')
{
tmp_key[i][y] = user_input[x];
x++;
y++;
}
i++;
}
}
}
tmp_key[i][y]='\0';
i=0;
for(x = 0;user_input[x] !='\0';x++) //I think my problem is starting from here.
{
if (user_input[x] !='$')
{
final_string[j]=user_input[x];
j++;
}
else
{
x++;
if((user_input[x]== '{')&&(strncmp(tmp_key[i],env_key,sizeof(tmp_key))==0))
{
while(user_input[x]!='}')
{
x++;
}
strcat(final_string,env_val);
j=j+val_length;
}
else
{
final_string[j]=user_input[x];
j++;
}
}
}
printf("output result = %s \n",final_string);
}
int main() {
char s[100];
sprintf(s, "jack${ABC}zack${DEF}");
replace_env(s, "ABC=/home/fikrie/Documents");
replace_env(s, "DEF=/tmp");
if (strcmp(s, "jack/home/fikrie/Documentszack/tmp")==0) {
printf("pass\n");
} else {
printf("fail\n");
}
printf("--------------------------------------------------------\n");
return 0;
}
To make it more clearer, here are the result:
env_var = ABC=/home/fikrie/Documents
env_key = ABC
env_val = /home/fikrie/Documents
input = jack${ABC}zack${DEF}
after strcat result is = jack/home/fikrie/Documents
j value is 26
after strcat result is = jack/home/fikrie/Documentszack/home/fikrie/Documents
j value is 52
output result = jack/home/fikrie/Documentszack/home/fikrie/Documents
env_var = DEF=/tmp
env_key = DEF
env_val = /tmp
input = jack${ABC}zack${DEF}
output result = jack{ABC}zack{DEF}ocumentszack/home/fikrie/Documents
fail
--------------------------------------------------------
As you can see, ABC are sent into the replace_env function. And it does replace the ${ABC} properly, followed with a string zack.Then the problem occures where ${DEF} are replaced with ABC key and not maintained as ${DEF}
When the DEF are sent during the second call of replace_env function, things got more wierd. Both ABC and DEF are not recognized. Even worse, the character at the back are still there.
My expectation is:
For the first call of replace_env:
jack/home/Fikrie/Documentszack${DEF}
For the second call of replace_env:
jack/home/Fikrie/Documentszacl/tmp
after the strcmp passed, the final_string will be cleared again.
All help are really appreciated. I dont expect an answer. I prefer a knowledge or guidance rather than just solving it blankly. Just need a clear explanation on my fault because I have been editing this code for almost a month and everything looks so blurry now. I know there are ways to solve it using memory functions, allocation etc. But this task is about string manipulation. I am running this on Ubuntu OS. Sorry for my bad english.

I know you didn't ask for this, but consider this. Learning the C string functions is worth your time.
#include <stdio.h>
#include <string.h>
void sub(char *s, char *env, char *value) {
char buf[BUFSIZ], *src = s, *dst = buf;
int n = strlen(env);
while(*src) {
if(strncmp(src, env, n) == 0) {
dst += strlen(strcpy(dst, value));
src += strlen(env);
} else {
*dst++ = *src++;
}
}
*dst = 0;
strcpy(s, buf);
}
void replace_env(char *s, char *env) {
char copy[BUFSIZ], tmp[BUFSIZ];
strcpy(copy, env);
char *eq = strchr(copy, '=');
if(eq == 0) {
printf("No '=' found in '%s'\n", env);
return;
}
*eq = 0;
sprintf(tmp, "${%s}", copy);
sub(s, tmp, eq+1);
}
int main() {
char s[100];
sprintf(s, "jack${ABC}zack${DEF}");
replace_env(s, "ABC=/home/fikrie/Documents");
replace_env(s, "DEF=/tmp");
if (strcmp(s, "jack/home/fikrie/Documentszack/tmp")==0) {
printf("pass\n");
} else {
printf("fail\n");
}
printf("--------------------------------------------------------\n");
return 0;
}

Related

Runtime Error when soving the problems of leetcode 5. Longest Palindromic Substring

I just tried to use dp method to solve the longest palindromic substring problem, this is the souce code:
#include<stdio.h>
#include<string.h>
#include<malloc.h>
char* longestPalindrome(char *s)
{
int length=strlen(s);
if(length == 0)
{
return "";
}
if(length == 1)
{
return s;
}
int dp[length][length];
int i,j;
for(i=0;i<length;i++)
{
for(j=0;j<length;j++)
{
if (i>=j)
{
dp[i][j]=1;
}
}
}
int maxlen=1;
int len_now=0;
int start=0,fin=0;
for(len_now=1;len_now<length;len_now++)
{
for(i=0;i+len_now<length;i++)
{
j=i+len_now;
if(s[i] != s[j])
{
dp[i][j]=0;
}
else
{
dp[i][j]=dp[i+1][j-1];
if(dp[i][j])
{
if(len_now+1>maxlen)
{
maxlen=len_now+1;
start=i;
fin=j;
}
}
}
}
}
/*char result[maxlen];
strncpy(result, s+start,maxlen);
result[maxlen]='\0';
char *tao=result;
return tao;*/
//I firstly tried to use strncpy to copy the result into a new string, it works on my own computer(using mingw5), but it return NULL when I test it through leetcode, and then I find this solution as below:
char *result = (char*)malloc(sizeof(char)*(maxlen));
for(i = start,j = 0; j < maxlen; i++,j++)
{
result[j] = s[i];
}
result[j] = '\0';
return result;
}
int main()
{
char *s="abcba";
char *p;
p=longestPalindrome(s);
printf("%s\n",p);
}
but when I submited it, runtime erreur occurs, does anyone knows how to improve it? (in the documentation of leetcode, it says dp solution is accepted, so I think it should work)
also, I have a question that why when I return a char result[] type, when I tested on leetcode, it return NULL.
thanks a lot

How do you convert a relative path to an absolute path in C?

I am trying to make a suid application that will only execute ruby scripts located in a restricted folder. I have tried to do this using realpath(3) but it is only returning the first segment of the path. Below is my code...
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <string.h>
#define SUEXEC_STR_LEN 2048
#define RUBY_APP "/usr/bin/ruby"
#define DIRECTORY_SEPARATOR "/"
static void safepath(const char *path_in, char * path_out, int outlen) {
realpath(path_in, path_out);
}
int main ( int argc, char *argv[] )
{
char cmd[SUEXEC_STR_LEN];
char path_out[SUEXEC_STR_LEN];
char path_in[SUEXEC_STR_LEN];
char *cp = &cmd[0];
strncpy(cp, RUBY_APP, SUEXEC_STR_LEN - 1);
strncpy(path_in, DIRECTORY_SEPARATOR, SUEXEC_STR_LEN - 1);
strncat(path_in,argv[1],SUEXEC_STR_LEN - 1);
safepath(path_in,path_out,SUEXEC_STR_LEN - 1);
printf("path_in=%s path_out=%s\n",path_in,path_out);
setuid( 0 );
// system( cmd );
return 0;
}
This is an example of the result I'm getting
root#server01:/root/src# ./a.out foo/bar/../test
path_in=/foo/bar/../test path_out=/foo
This is the result I want
root#server01:/root/src# ./a.out foo/bar/../test
path_in=/foo/bar/../test path_out=/foo/test
You should check for realpath()'s return value. As described in its man page,
RETURN VALUE
If there is no error, realpath() returns a pointer to the resolved_path.
Otherwise it returns a NULL pointer, and the contents of the array resolved_path are undefined. The global variable errno is set to indicate the error.
Also in ERRORS section of its man page,
ENOENT The named file does not exist.
Thus, if there is indeed no /foo/test in your file system, realpath() should return NULL and the output is undefined.
So, here's a working sketch of how you might go about it in C on Linux. This is a quick hack that I do not represent as being exemplary code, efficient, etc. It (ab)uses PATH_MAX, uses “bad” string functions, and may leak memory, eat your cat, and have corner cases that segfault, etc. When it breaks, you get to keep both parts.
The basic idea is to go through the given path, breaking it up into “words” using “/” as the delimiter. Then, go through the list, pushing the “words” onto a stack, but ignoring if empty or “.”, and popping if “..”, then serializing the stack by starting at the bottom and accumulating a string with slashes in between.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <linux/limits.h>
typedef struct stack_s {
char *data[PATH_MAX];
int top;
} stack_s;
void stack_push(stack_s *s, char *c) {
s->data[s->top++] = c;
}
char *stack_pop(stack_s *s) {
if( s->top <= 0 ) {
return NULL;
}
s->top--;
return s->data[s->top];
}
// DANGER! DANGER! Returns malloc()ed pointer that you must free()
char *stack_serialize(stack_s *s) {
int i;
char *buf;
int len=1;
for(i=0; i<s->top; i++) {
len += strlen(s->data[i]);
len++; // For a slash
}
buf = malloc(len);
*buf = '\0';
for(i=0; i<s->top-1; i++) {
strcat(buf, s->data[i]);
strcat(buf, "/");
}
strcat(buf, s->data[i]);
return buf;
}
// DANGER! DANGER! Returns malloc()ed pointer that you must free()
char *semicanonicalize(char *src) {
char *word[PATH_MAX] = {NULL};
int w=0;
int n_words;
char *buf;
int len;
char *p, *q;
stack_s dir_stack = {{NULL},0};
// Make a copy of the input string:
len = strlen(src);
buf = strdup(src);
// Replace slashes with NULs and record the start of each "word"
q = buf+len;
word[0]=buf;
for(p=buf,w=0; p<q; p++) {
if(*p=='/') {
*p = '\0';
word[++w] = p+1;
}
}
n_words=w+1;
// We push w[0] unconditionally to preserve slashes and dots at the
// start of the source path:
stack_push(&dir_stack, word[0]);
for(w=1; w<n_words; w++) {
len = strlen(word[w]);
if( len == 0 ) {
// Must've hit a double slash
continue;
}
if( *word[w] == '.' ) {
if( len == 1 ) {
// Must've hit a dot
continue;
}
if( len == 2 && *(word[w]+1)=='.' ) {
// Must've hit a '..'
(void)stack_pop(&dir_stack);
continue;
}
}
// If we get to here, the current "word" isn't "", ".", or "..", so
// we push it on the stack:
stack_push(&dir_stack, word[w]);
}
p = stack_serialize(&dir_stack);
free(buf);
return p;
}
int main(void)
{
char *in[] = { "/home/emmet/../foo//./bar/quux/../.",
"../home/emmet/../foo//./bar/quux/../.",
"./home/emmet/../foo//./bar/quux/../.",
"home/emmet/../foo//./bar/quux/../."
};
char *out;
for(int i=0; i<4; i++) {
out = semicanonicalize(in[i]);
printf("%s \t->\t %s\n", in[i], out);
free(out);
}
return 0;
}
This is the code which I used as a solution to the problem. It may have some bugs remaining in it, and it isn't checking the outlen argument to avoid segfaults and other uglyness but it seems to get the job done.
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <string.h>
#include <linux/limits.h>
#define SUEXEC_STR_LEN 2048
#define RUBY_APP "/usr/bin/ruby"
#define DIRECTORY_SEPARATOR "/"
#define RUBY_EXT ".rb"
#define SERVICES_BASE_PATH "/path/to/ruby/services"
static inline int isDirSeparator(const char c) { return (c == '/' || c == '\\'); }
static void safepath(const char *path_in, char * path_out, int outlen)
{
char *dirs[PATH_MAX];
int depth = 0;
char *dstptr = path_out;
const char *srcptr = path_in;
*dstptr++ = DIRECTORY_SEPARATOR[0];
dirs[0] = dstptr;
dirs[1] = NULL;
depth++;
while (1) {
if ((srcptr[0] == '.') && isDirSeparator(srcptr[1])) {
srcptr += 2;
} else if (srcptr[0] == '.' && srcptr[1] == '.' && isDirSeparator(srcptr[2])) {
if (depth > 1) {
dirs[depth] = NULL;
depth--;
dstptr = dirs[depth-1];
} else {
dstptr = dirs[0];
}
srcptr += 3;
} else if (srcptr[0] == '.' && srcptr[1] == '.' && srcptr[2] == 0) {
if (depth == 1) {
srcptr += 2;
} else {
depth--;
dstptr = dirs[depth-1];
srcptr += 2;
}
} else {
while (!isDirSeparator(srcptr[0]) && srcptr[0]) {
*dstptr++ = *srcptr++;
}
if (srcptr[0] == 0) {
if (dstptr != dirs[0] && isDirSeparator(dstptr[-1])) {
dstptr[-1] = 0;
}
dstptr[0] = 0;
return;
} else if (isDirSeparator(srcptr[0])) {
if (dstptr == dirs[0]) {
srcptr++;
} else {
*dstptr++ = *srcptr++;
dirs[depth] = dstptr;
depth++;
}
while (isDirSeparator(srcptr[0]) && srcptr[0]) {
srcptr++;
}
} else {
path_out[0] = 0;
return;
}
}
}
}
int main ( int argc, char *argv[] )
{
int ret;
char cmd[SUEXEC_STR_LEN];
char path_out[SUEXEC_STR_LEN];
char path_in[SUEXEC_STR_LEN];
char *cp = &cmd[0];
if (argc < 2) {
fprintf(stderr,"usage: %s <service>\n",argv[0]);
return 1;
}
strncpy(cp, RUBY_APP, SUEXEC_STR_LEN - 1);
strncpy(path_in, DIRECTORY_SEPARATOR, SUEXEC_STR_LEN - 1);
strncat(path_in,argv[1],SUEXEC_STR_LEN - 1);
safepath(path_in,path_out,SUEXEC_STR_LEN - 1);
//printf("path_in=%s path_out=%s\n",path_in,path_out);
strncat(cmd," ",SUEXEC_STR_LEN - (1+sizeof(RUBY_EXT)));
strncat(cmd,SERVICES_BASE_PATH,SUEXEC_STR_LEN - (1+sizeof(RUBY_EXT)));
strncat(cmd,path_out,SUEXEC_STR_LEN - (1+sizeof(RUBY_EXT)));
strncat(cmd,RUBY_EXT,SUEXEC_STR_LEN - 1);
setuid( 0 );
ret = system( cmd );
if (ret == -1) {
return ret;
}
ret = WEXITSTATUS(ret);
return ret;
}

Segmentation fault (core dumped)...BMH Algorithm

I am trying to implement a Boyer Moore Horsepoole algorithm. This code was written in Turbo C++, Windows. It worked. I have to port this in ubuntu.
typedef struct skip_table
{
char index;
int value;
}skip_table;
void create_table(char*,int);
int discrete_char(char*,int);
int bm(char*, char*);
int lookup(char);
int check_EOF(char*,int);
skip_table *t1;
int tab_len;
FILE *fptr;
int main()
{
time_t first, second;
double time_spent;
long int cnt=0;
char *key_string,*buf,c; // String to be matched and text
int i,key_len,text_len,def_shift_len,flag_match=0;
gets(key_string);
key_len=strlen(key_string);
fptr=fopen("test_file.txt","r");
first = clock();
fseek(fptr,SEEK_SET,0);
create_table(key_string,key_len);
while(flag_match!=1)
{
fseek(fptr,100*cnt,0);
fread(buf,100-key_len-1, 1, fptr);
flag_match = bm(buf, key_string);
cnt++;
printf("\n%d",cnt);
}
second =clock();
time_spent=(double)(second-first)/CLOCKS_PER_SEC;
if(flag_match==1)
printf("\n\nMatch Found in %lf seconds",time_spent);
else
printf("\n\nMatch NOT Found in %lf seconds",time_spent);
fclose(fptr);
return 0;
}
int discrete_char(char* key_string,char* temp,int key_len)
{
int i,j,count=1,flag=0;
for(i=1;i<key_len;i++)
{
for(j=0; j<count; j++)
{
flag=0;
if(temp[j] == key_string[i])
{
flag=1;
break;
}
}
if(flag!=1)
{
temp[count++]=key_string[i];
flag=0;
}
}
temp[count]='\0';
return count;
}
void create_table(char* key_string,int key_len)
{
int i,j,k,max_index;
char *temp;
temp[0] = key_string[0];
tab_len=discrete_char(key_string,temp,key_len);
t1=(skip_table*)malloc((tab_len-1)*sizeof(skip_table));
for(i=0;i<tab_len;i++)
{
for(j=0;j<key_len;j++)
{
if(temp[i]==key_string[j])
max_index=j;
}
t1[i].index=temp[i];
t1[i].value=key_len-max_index-1;
printf("\n\n %c %d",t1[i].index,t1[i].value);
}
}
int bm(char* text, char* key_string)
{
int i_t, i_k, j,k, text_len, key_len, shift, count=0, flag_match=0;
int loop_count;
text_len = strlen(text);
key_len = strlen(key_string);
i_t=key_len;
i_k=key_len;
loop_count=0;
while(i_t<=text_len)
{
if(count != key_len)
{
if(text[i_t-1]==key_string[i_k-1])
{
count++;
i_t--; i_k--;
loop_count++;
}
else
{
if(loop_count>key_len)
{
i_t=i_t+lookup(text[i_t-1])+1;
i_k=key_len;
loop_count=0;
continue;
}
shift = lookup(text[i_t-1]);
if(shift<=0)
shift=key_len;
i_t = i_t+shift;
i_k = key_len;
count=0;
}
}
else
{
flag_match = 1;
break;
}
}
return flag_match;
}
"int lookup(char index)" returns the respective value field of the index if present in "temp" else returns -1.
There's my whole code.
Not that I see exactly what went wrong but here are some defensive programming tips:
int main()
{
// initialize all variables before use
time_t first = 0, second = 0;
double time_spent = 0.0;
long int cnt=0;
char *key_string = NULL;
char *buf = NULL;
char c = '\0';
char temp[50] = {0};
int i = 0,key_len=0,text_len=0,def_shift_len=0,flag_match=0;
// use fgets instead of gets, fgets allows you specify max length
fgets(temp,sizeof(temp),stdin);
key_len=strlen(temp);
key_string = (char*) malloc(key_len+1);
// use strncpy or strcpy_s to specify max size
strncpy(key_string, temp, sizeof(key_string));
fptr = fopen("test_file.txt","r");
first = clock();
// here arguments have wrong order, fseek takes origin as last arg:
fseek(fptr,0,SEEK_SET);
// could be something in create_table, but you have not supplied it
create_table(key_string,key_len);
When you have so many variables in a function you may consider moving out parts of the function to other functions
Try using --track-origins=yes on your valgrind options as well, as the output suggests, this can help track down where uninitialised varables have come from.
As others have suggested, the issue valgrind is reporting is inside create_table, so please post the code for that as well.

Segmentation fault while copying the string

I am trying to execute the below code, but for every attempt I am geting a segmentation fault. The problem seems to be coming from the strncpy function used in tokenizing. I a bit new to programming. Please help me debug the code. Please help:
/*
** Program to accept a binary IP address from the command line and
** if it is a valid IP address, show the user its dotted decimal form.
** Also tell the user, which class of IP address it belongs to
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#define TRUE 1
#define FALSE 0
int validchk(char uarg[]);
int tokenize(char uarg[], char* uargv[]);
int toNum(char harr[], char iparr[]);
void shownum(char *iparr[]);
void classify(char uarg[]);
void usage();
void mystrncpy(char* arr, char* brr);
int main(int argc, char *argv[])
{
char* ipStr[9];
if (argc != 2) {
usage();
exit(1);
}
if (validchk(argv[1]) == FALSE) {
fprintf(stderr,"Error in the length of the IP Bit Address\n");
exit(1);
}
classify(argv[1]);
if (tokenize(argv[1],ipStr) == -1) {
perror("Error in tokenizing the binary IP address\n");
}
//shownum(ipStr);
return 0;
}
void usage()
{
fprintf(stderr,"Usage: bi2ip <32bitip>\n");
return;
}
int validchk(char uarg[])
{
if (strlen(uarg) != 32) {
return FALSE;
}
}
void classify(char uarg[])
{
int ipcnt = 0;
char *p;
int doneflag = FALSE;
while(ipcnt <= 4) {
p = &uarg[ipcnt];
if (*p == '0') {
doneflag = TRUE;
break;
}
ipcnt++;
}
if (doneflag == FALSE) {
fprintf(stderr,"Failed to classify\n");
exit(1);
}
printf("%c\n",('A'+ipcnt));
return;
}
int tokenize(char uarg[], char* uargv[])
{
int i =0,j;
// for (i = 0; i <4; i++) {
// strncpy(&uargv[i][0],&uarg[j],8);
//strncpy(uargv[1],&uarg[8],8);
//strncpy(uargv[2],&uarg[16],8);
//strncpy(uargv[3],&uarg[24],8);
// uargv[i][8] = '\0';
// j+=8;
for ( j = 0; j<8; j++) {
uargv[0][j] = uarg[j];
uargv[1][j] = uarg[j+8];
uargv[2][j] = uarg[j+16];
uargv[3][j] = uarg[j+24];
}
// }
return 0;9
}
void shownum(char *iparr[])
{
int i,j;
unsigned long arr[4];
for(i = 0; i<4; i++) {
arr[i] = strtoul(iparr[i],NULL,2);
}
for ( j = 0; j < 3; j++) {
printf("%lu.",arr[j]);
}
printf("%lu",arr[3]);
}
char* ipStr[9];
The above creates an array of 9 strings (pointers to char). It does not, however, allocate memory for the nine strings.
When you strncpy into ipStr, your program segfaults.
Solution: allocate memory (e.g. using malloc() or strdup()).
Your validchk() function fails to return TRUE if the address validates. This will make it behave more or less randomly.
You should rewrite it, keeping the same core validation rule, as:
int validchk(const char *string)
{
return (string != NULL) && (strlen(string) == 32);
}

splitting a full filename into parts

I am creating a function that will split a full unix filename(like /home/earlz/test.bin) into its individual parts. I have got a function, and it works for the first two parts perfect, but after that it produces erroneous output...
strlcpy_char will copy a string using term as the terminator, as well as 0.
If it is terminated with term, then term will be the last character of the string, then null.
returns trg string length...
int strlcpy_char(char *trg,const char *src,int max,char term){
int i;
if(max==0){return 0;}
for(i=0;i<max-1;i++){
if(*src==0){
*trg=0;
return i;
}
if(*src==term){
*trg=term;
trg++;
*trg=0; //null terminate
return i+1;
}
*trg=*src;
src++;
trg++;
}
*trg=0;
return max;
}
.
int get_path_part(char *file,int n,char *buf){
int i;
int current_i=0;
//file is assumed to start with '/'so it skips the first character.
for(i=0;i<=n;i++){
current_i++;
current_i=strlcpy_char(buf,&file[current_i],MAX_PATH_PART_SIZE,'/');
if(current_i<=1){ //zero length string..
kputs("!"); //just a debug message. This never happens with the example
return -1; //not enough parts to the path
}
}
if(buf[current_i-1]=='/'){
return 1; //is not the last part
}else{
return 0; //is the last part(the file part)
}
}
I use this code to test it:
kputs("test path: ");
kgets(cmd);
kputs("\n");
char *tmp=malloc(256);
int i=0;
get_path_part(cmd,i,tmp);
kputs(tmp);
kputs("\n");
i=1;
get_path_part(cmd,i,tmp);
kputs(tmp);
kputs("\n");
i=2;
get_path_part(cmd,i,tmp);
kputs(tmp);
kputs("\n");
When I try something like "/home/test.bin" it works right outputting
/home
/test.bin
But when I try "/home/earlz/test.bin" I get
/home
/earlz
/arlz
Anyone see the problem in my code, as I've been looking but I just can't see any problem.
Also, before you say "but there is a library for that" I am doing this in an operating system kernel, so I barely have a standard library. I only have parts of string.h and really that's about it for standard.
You overwrite current_i instead of adding it up as you walk through the path.
So
current_i++;
current_i=strlcpy_char(buf,&file[current_i],MAX_PATH_PART_SIZE,'/');
should really be
current_i += strlcpy_char(buf,&file[current_i+1],MAX_PATH_PART_SIZE,'/');
I think you need to track your current_i for i>1 since the max value returned from the strlcpy has no idea of where you are in the overall file string. does it make sense?
current_i=strlcpy_char(buf,&file[current_i],MAX_PATH_PART_SIZE,'/');
Don't you need to do something like
tocurrent_i += strlcpy_char...
instead of
tocurrent_i = strlcpy_char...
Does your code have to be re-entrant?
If not use strtok, it is in strings.h
STRTOK(P)
NAME
strtok, strtok_r - split string into tokens
SYNOPSIS
#include <string.h>
char *strtok(char *restrict s1, const char *restrict s2);
char *strtok_r(char *restrict s, const char *restrict sep,
char **restrict lasts);
Sorry for not commenting on your code though :)
If you are using Glib, g_strsplit is very nice and easy to use.
This is how I'd do it
char ** split_into_parts(char *path) {
char ** parts = malloc(sizeof(char *) * 100);
int i = 0;
int j = 0;
if (*path == '/') {
path++;
}
parts[0] = 0;
while (*path) {
if (*path == '/') {
parts[i][j] = 0;
i++;
parts[i] = 0;
j = 0;
} else {
if (parts[i] == 0) {
parts[i] = malloc(sizeof(char) * 100);
}
parts[i][j] = *path;
j++;
}
path++;
}
parts[i+1] = 0;
return parts;
}
Try something like the code I have below.
If you need implementations of standard C functions (like strchr()) try koders.com or just google for strchr.c.
#include <stdio.h>
#include <string.h>
const char *NextToken(const char *pStart, char chSep, char *pToken, size_t nTokMax)
{
const char *pEnd;
size_t nLength;
/* set output to empty */
*pToken=0;
/* make sure input is OK */
if (!pStart || *pStart!=chSep)
return NULL;
/* find end of token */
pEnd = strchr(pStart+1, chSep);
if (pEnd)
nLength = pEnd - pStart;
else
nLength = strlen(pStart);
if (nLength >= nTokMax) /* too big */
return NULL;
strncpy(pToken, pStart, nLength);
pToken[nLength] = 0;
return pEnd;
}
int main()
{
#define BUFFSIZE 256
char cmd[BUFFSIZE];
char tmp[BUFFSIZE];
const char *pStart=cmd;
int i=0;
puts("test path: ");
fgets(cmd, BUFFSIZE, stdin);
puts("");
do {
pStart = NextToken(pStart, '/', tmp, BUFFSIZE);
if (tmp[0])
puts(tmp);
} while (pStart);
return 0;
}

Resources