C - Obtaining directory path - c

I'm writing a program that when executed in a directory will generate a text file with all of the contents in that directory. I'm getting the directory path from the **argv to main and because I'm using netbeans and cygwin I have to do some string manipulation of the obtained path in my char* get_path(char **argv) function. The directory path size will always vary therefore I'm assigning space with malloc to store it in the memory.
Program snippet:
#include <stdio.h>
#include <stdlib.h>
#include <dirent.h>
#include "dbuffer.h" //my own library
#include "darray.h" //my own library
ARR* get_dir_contents( char* path)
{
DBUFF *buff = NULL;
ARR *car = NULL;
DIR *dir_stream = NULL;
struct dirent *entry = NULL;
dir_stream = opendir(path);
if(opendir(path)==NULL) printf("NULL");
//... more code here
return car;
}
char* get_path(char **argv)
{
char *path = malloc(sizeof(char)* sizeof_pArray( &argv[0][11] ) + 3 );
strcpy(path, "C:");
strcat(path, &argv[0][11]);
printf("%s, sizeof: %d \n",path, sizeof_pArray(path));
return path;
}
int main(int argc, char** argv)
{
char *p = get_path(argv);
ARR *car = get_dir_contents(&p[0]);
//... more code here
return (EXIT_SUCCESS);
}
The problem is that the string that I have doesn't initialize the dir_stream pointer. I suspect it is because of some discrepancy between pointers and string literals but I can't pinpoint what it is exactly. Also the fact that dirent library function expects DIR *opendir(const char *dirname); const char might have something to do with it.
Output:
C:/Users/uk676643/Documents/NetBeansProjects/__OpenDirectoryAndListFiles/dist/Debug/Cygwin_4.x-Windows/__opendirectoryandlistfiles, sizeof: 131
NULL
RUN FAILED (exit value -1,073,741,819, total time: 2s)

there are some things here that can go wrong so
I would suggest doing something like this instead
char* get_path(char *argv)
{
char *path = malloc(sizeof(char)* strlen(argv) );
if (path != NULL)
{
strcpy(path, "C:");
strcat(path, argv + 11);
printf("%s, sizeof: %d \n",path, strlen(path));
}
return path;
}
...
char* p = get_path(*argv);
note: you don't need the extra 3 bytes, since you allocate including the 11 bytes you later skip. although instead of having the 11 bytes offset you may want to decompose the string and then later put it together so that it is portable. E.g. using strtok you could split that path and replace the parts you don't need.

Could it be a simple confusion about argv ? Please insert the following lines
just at the beginning of your main() , is it what you expected ?
printf("\n argv[0]== %s" , argv[0] );
getchar();
printf("\n argv[1]== %s" , argv[1] );
getchar();
OK, so we work from argv[0] , please try this for get_path
char *get_path(char *argv)
{
int i=0;
// +2 to add the drive letter
char *path = malloc(sizeof(char)* strlen(argv)+2 );
if (path != NULL)
{
strcpy(path, "C:");
strcat(path, argv);
// we get the path and the name of calling program
printf("\n path and program== %s",path);
printf("%s, sizeof: %d \n",path, strlen(path));
// now remove calling program name
for( i=strlen(path) ; ; i--)
{
// we are working in windows
if(path[i]=='\\') break;
path[i]='\0';
}
}
return path;
}

Related

Function strtok() does not work with strcat() (illegal hardware instruction)

I'm new at c and I'm writing a script that inputs a file path as arguments. I want to have the last element of the path and the rest of the path.
Here is what I wrote:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char *argv[])
{
char *file = argv[1];
char base[sizeof(file)] = "";
char *tok = strtok(file, "/");
while (tok != NULL)
{
strcat(base, tok);
tok = strtok(NULL, "/");
}
printf("Base folder: %s\n", base);
printf("Last element: %s\n", tok);
return 0;
}
Input: ./getlast /this/is/some/path/file.txt
Expected result:
Base folder: /this/is/some/path
Last element: file.txt
It gives me this error when I concatenate base with tok:
[1] 15245 illegal hardware instruction ./getlast /Users/<myusername>/Desktop/getlast/getlast.c
I keep trying different solutions but I can't figure out what is wrong.
(I haven't a good English so sorry for that)
To use strtok() for this task would be complicated.
Determining which is the last token (filename) involves not commiting to concatentating until the next token is retrieved from the string.
One could 'hang onto' one pointer and append when another token is found, but that's confusing.
To find what might be called "the last token", strrchr() is perfectly suited to the task.
I regard "enviroment vars" (like argv) to be readonly, so strdup() makes a working copy that can be altered with impunity.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void main( int argc, char *argv[] ) {
if( argc != 2 ) { // always test before using
printf( "Bad usage\n" );
return;
}
char *copy = strdup( argv[1] ); // temp working copy to manipulate
char *lastSep = strrchr( copy, '/' ); // find LAST slash char
if( lastSep == NULL )
printf( "No prefix path: %s\n", argv[1] );
else {
*lastSep++ = '\0'; // split into two strings
printf( "Base folder: %s\n", copy );
printf( "Last element: %s\n", lastSep );
}
free( copy );
}
Update
You can avoid the overhead of making a working copy by capitalising on some pointer arithmetic and printf()'s length specifiers. Here's another way to achieve the same thing without using the heap:
char *p = "/one/two/three/four.txt";
char *lastSep = strrchr( p, '/' ); // find LAST slash char
if( lastSep == NULL )
printf( "No prefix path: %s\n", p );
else {
printf( "Base folder: %.*s\n", lastSep - p, p );
printf( "Last element: %s\n", lastSep + 1 );
}

strcpy is not working well with pointer array

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[])
{
char *ptr;
char temp[20];
if (strlen(argv[1]) < strlen(argv[2]))
{
strcpy(temp,argv[1]);
strcpy(argv[1],argv[2]);
strcpy(argv[2],temp);
}
ptr = strstr(argv[1],argv[2]);
if (ptr == NULL)
printf("Non-inclusive");
else
printf("%s is part of %s", argv[2], argv[1]);
return 0;
}
When I enter "abc abcd",
I want to get "abc is part of abcd" as a result,
but real result is "abc is part of abcdabc"
The length of each string in the argv array is fixed. So when you attempt to swap the contents of argv[1] and argv[2] when their sizes are different you write past the end of the shorter one. This triggers undefined behavior.
Better to use separate char * variables, one pointing the longer string and one pointer to the shorter.
int main(int argc, char *argv[])
{
char *ptr;
char *s_short, *s_long;
if (strlen(argv[1]) < strlen(argv[2])) {
s_short = argv[1];
s_long = argv[2];
} else {
s_short = argv[2];
s_long = argv[1];
}
ptr = strstr(s_long,s_short);
if (ptr == NULL)
printf("Non-inclusive");
else
printf("%s is part of %s", s_short, s_long);
return 0;
}

strtok when process two strings at same time

New in C and pretty confused about how to deal with several strings at the same time using strtok, for a simply example, I want to use strtok to extract the number and compare then.
#include <stdio.h>
#include <string.h>
int main()
{
char s1[100]="11.54";
char s2[100]="12.55";
const char tok[2]=".";
char* token1=strtok(s1,tok);
char* token2=strtok(s2,tok);
while(token1 !=NULL && token2 !=NULL){
int temp=strcmp(token1,token2);
if(temp==0){
token1=strtok(NULL,tok);
token2=strtok(NULL,tok);
}
else if(temp<0){
printf("%d\n",-1);
return;
}
else{
printf("%d\n",1);
return;
}
}
if(token1 !=NULL){
printf("%d\n",1);
return;
}
if(token2 !=NULL){
printf("%d\n",-1);
return;
}
printf("%d\n",0);
return 0;
}
But when I use the strtok, the strtok(NULL,token)will point to the current string and will do like: 11->12>55->NULL and skip the 54
How could I deal with such situation? Thanks!!
Do not use strtok(). The documentation will tell you strtok() is not reentrant (i.e. should not be used across threads), but perhaps less obvious is the fact that the reason it is not reentrant is because it uses an internal save variable to remember where it's got to. That means you also can't use two instances at once. Instead use strtok_r() or failing that strsep() might work.
strtok_r() is just like strtok, save that you pass it a char ** (i.e. a pointer to char *) where it can save where it's got to.
The GNU libc manual page gives a good example of using a nested strtok_r which is what you are trying to do:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int
main(int argc, char *argv[])
{
char *str1, *str2, *token, *subtoken;
char *saveptr1, *saveptr2;
int j;
if (argc != 4) {
fprintf(stderr, "Usage: %s string delim subdelim\n",
argv[0]);
exit(EXIT_FAILURE);
}
for (j = 1, str1 = argv[1]; ; j++, str1 = NULL) {
token = strtok_r(str1, argv[2], &saveptr1);
if (token == NULL)
break;
printf("%d: %s\n", j, token);
for (str2 = token; ; str2 = NULL) {
subtoken = strtok_r(str2, argv[3], &saveptr2);
if (subtoken == NULL)
break;
printf(" --> %s\n", subtoken);
}
}
exit(EXIT_SUCCESS);
}

segmentation fault when manipulating strings?

this peace of code summarizes the problem that I have.i want to copy a file from a source to a specified destination which i'm allowed to change it's name it's a function that's integrated in an application i'm trying to create that manages files
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
void concatenate_string(char *original, char *add)
{
while(*original!='\0')
original++;
while(*add!='\0')
{
*original = *add;
add++;
original++;
}
*original = '\0';
}
int main(int argc,char *argv[])
{
char *nom;
char *path;
printf("entrer a name \n");
scanf("%s",nom);
printf("entrer a pathh \n");
scanf("%s",pathh);
char *dest=(char*)malloc(strlen(nomm)+46+1);
strcat(dest,"/home/ridaamine/Desktop/app/application/Files/");
strcat(dest,nom);
char *comand=(char*)malloc(strlen(name)+8+strlen(path)+1);
strcat(comand,"cp -via ");
strcat(comand,path);
strcat(comand," ");
strcat(comand,name);
system(comand);
}
You didn't initialize nom
scanf("%s",nom);
either
nom = malloc(SOME_SIZE);
and then, let's say SOME_SIZE == 100
scanf("%99s", nom);
or
char nom[SOME_SIZE];
and then, also let's say SOME_SIZE == 100
scanf("%99s", nom);
and of course the same applies to path.
The second solution is better because it's faster not that much and you don't need to free(nom) after using it. The second case could be needed in the rare case where the size of the string is so large (> 8M) it would overflow the stack.
And as Weather Vane points out strcat has a problem too you should use strcpy the first time
strcat(dest,"/home/ridaamine/Desktop/app/application/Files/");
strcat(dest,nom);
shoul be
strcpy(dest,"/home/ridaamine/Desktop/app/application/Files/");
strcat(dest,nom);
and clearly this time, the same applies to command.
Finally you have a space that you didn't count in
malloc(strlen(dest) + 8 + strlen(path) + 1 + 1 /* space " " */)
Tip: you don't need to cast malloc so don't, it could hide a potential bug. And always check that malloc didn't return NULL, before dereferencing the pointer.
You should call free after you are done too, this is your own code fixed
int main(int argc,char *argv[])
{
char nom[100];
char path[100];
char _path[] = "/home/ridaamine/Desktop/app/application/Files/";
char cp[] = "cp -via ";
char space[] = " ";
printf("entrer a name \n");
scanf("%99s", nom);
printf("entrer a path \n");
scanf("%99s", path);
char *dest = malloc(strlen(nom) + strlen(_path) + 1);
if (dest == NULL)
{
printf("no more memory left.\n");
return -1;
}
strcpy(dest, _path);
strcat(dest, nom);
char *comand = malloc(strlen(dest) + strlen(cp) + strlen(space) + strlen(path) + 1);
if (command == NULL)
{
free(dest);
printf("no more memory left.\n");
return -1;
}
strcpy(comand, cp);
strcat(comand, path);
strcat(comand, space);
strcat(comand, dest);
free(dest);
system(comand);
free(command);
return 0; // always return from main
}
The first strcat() must in each case be changed to strcpy() because the strings have not been initialised to the empty string. And the first string dest will certainly be too short.
char *dest=(char*)malloc(strlen(nomm)+46+1); // this is too short
strcpy(dest,"/home/ridaamine/Desktop/app/application/Files/");
strcat(dest,nom);
char *comand=(char*)malloc(strlen(name)+8+strlen(path)+1);
strcpy(comand,"cp -via ");
strcat(comand,path);
strcat(comand," ");

Getting folder from a path

Let's say that I have a path as a string (like this one):
/ROOT/DIRNAME/FILE.TXT
How can I get the parent folder of file.txt (DIRNAME in this case)?
For a path that should have at least one directory in it:
char str[1024]; // arbitrary length. just for this example
char *p;
strcpy(str, "/ROOT/DIRNAME/FILE.TXT"); // just get the string from somewhere
p = strrchr(str, '/');
if (p && p != str+1)
{
*p = 0;
p = strrchr(p-1, '/');
if (p)
print("folder : %s\n", p+1); // print folder immediately before the last path element (DIRNAME as requested)
else
printf("folder : %s\n", str); // print from beginning
}
else
printf("not a path with at least one directory in it\n");
Locate last occurrence of / using strrchr. Copy everything from beginning of string to the found location. Here is the code:
char str[] = "/ROOT/DIRNAME/FILE.TXT";
char * ch = strrchr ( str, '/' );
int len = ch - str + 1;
char base[80];
strncpy ( base, str, len );
printf ( "%s\n", base );
Working just with string; no knowledge of symlink or other types assumed.
You can also do it simply using pointers. Just iterate to the end of the path and then backup until you hit a /, replace it with a null-terminating char and then print the string:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main (int argc, char *argv[]) {
if (argc < 2 ) {
fprintf (stderr, "Error: insufficient input, usage: %s path\n", argv[0]);
return 1;
}
char *path = strdup (argv[1]);
char *p = path;
while (*p != 0) p++;
while (--p)
if (*p == '/') {
*p = 0;
break;
}
printf ("\n path = %s\n\n", path);
if (path) free (path);
return 0;
}
output:
$ ./bin/spath "/this/is/a/path/to/file.txt"
path = /this/is/a/path/to

Resources