I am using the stat.h header and stat() to read and list files and directories in a directory. I've tried my code with different preset directories to see the result and print the corresponding type of the entry and so far in each test the code shows the current directory and 2 sub directories as directories but shows the other directories as files despite having the correct path listed alongside it
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <dirent.h>
#include <locale.h>
#include <sys/stat.h>
#include <wchar.h>
extern int errno;
int main(int argc, char *argv[]) {
setlocale(LC_ALL,"Turkish");
DIR* dp;
struct dirent dirp;
char test[9999];
getcwd(test,9999);
printf("FOLDERMAIN:%s\n",test);
dp=opendir(".");
searchDirectoryForString(dp,"Mat",test);
return 0;
}
void searchDirectoryForString(DIR* dp,char* str,char* directoryname)
{
int lineno=1,num=0;
FILE* fp;
struct dirent *file;
char temp[99999];
char buf[99999];
char *rpath;
rpath = calloc(99999,1);
char path[99999];
char* temppath;
temppath = calloc(99999,1);
int count = 0;
char dirhold[100];
char* dot;
int line_num = 1;
int find_result=0;
static int check=0;
DIR* fdp;
if(dp==NULL)
{
printf("cant open");
}
struct stat filestat;
while (file=readdir(dp)) {
stat(file->d_name,&filestat);
//printf("%s\n",file->d_name);
if(strcmp(file->d_name,"..")==0||(strcmp(file->d_name,".")==0))
continue;
if ( S_ISDIR(filestat.st_mode))
{
check++;
printf("\n CHECK: %d\n",check);
if(check!=1)
{
strcpy(temppath,directoryname);
printf("temp:%s\n",directoryname);
strcat(directoryname,"\\");
strcat(directoryname,file->d_name);
dot = strrchr(directoryname, '\\');
strcpy(dirhold,dot);
printf("DIR: %s\n",dirhold);
printf("%s KLASÖR\n",directoryname);
chdir(directoryname);
dp=opendir(directoryname);
if(dp==NULL)
{
printf("2\n");
}
strcat(temppath,dirhold);
searchDirectoryForString(dp,str,temppath);
}
else{
strcpy(path,directoryname);
strcat(directoryname,"\\");
strcat(directoryname,file->d_name);
dot = strrchr(directoryname, '\\');
strcpy(dirhold,dot);
printf("DIR: %s\n",dirhold);
printf("%s FOLDER\n",directoryname);
chdir(directoryname);
dp=opendir(directoryname);
if(dp==NULL)
{
printf("2\n");
}
strcat(path,dirhold);
searchDirectoryForString(dp,str,path);
}
}
else
{
snprintf(buf,99999,"%s",directoryname);
strcat(buf,"\\");
//strcat(directoryname,dirhold);
strcat(buf,file->d_name);
printf("%s FILE \n",buf);
//Close the file if still open.
if(fp) {
fclose(fp);
strcpy(rpath," ");
}
}
}
}
}
I tried my best to produce an MCVE below. One new thing i noticed is if i add another folder to a preset folder it is not recognized as a folder. If i add a folder to a folder which is one of the recognized folders it is also recognized as a folder(nested folder) the issue is most likely caused by the stat function so wrote another function for it to be able to seen more clearly as its in its own scope. Im using devc++ as my IDE.
#include <locale.h>
#include <unistd.h>
#include <dirent.h>
#include <stdio.h>
#include <sys/stat.h>
#include <wchar.h>
int main(int argc, char *argv[]) {
setlocale(LC_ALL,"Turkish");
DIR* dp;
struct dirent dirp;
char test[9999];
getcwd(test,9999);
printf("FOLDERMAIN:%s\n",test);
dp=opendir(".");
listDir(dp,test);
return 0;
}
int isDir(const char *name) {
struct stat fileStat;
return !stat(name, &fileStat) && S_ISDIR(fileStat.st_mode);
}
void listDir(DIR* dp,char* directoryname)
{
struct dirent *file;
char buf[99999];
char* temppath;
temppath = calloc(99999,1);
int count = 0;
char dirhold[100];
char* dot;
int line_num = 1;
int find_result=0;
static int check=0;
char* dir;
DIR* fdp;
if(dp==NULL)
{
printf("cant open");
}
while (file=readdir(dp)) {
//printf("%s\n",file->d_name);
if(strcmp(file->d_name,"..")==0||(strcmp(file->d_name,".")==0))
continue;
if (isDir(file->d_name))
{
check++;
printf("\n CHECK: %d\n",check);
strcpy(temppath,directoryname);
printf("temp:%s\n",directoryname);
strcat(directoryname,"\\");
strcat(directoryname,file->d_name);
dot = strrchr(directoryname, '\\');
strcpy(dirhold,dot);
printf("DIR: %s\n",dirhold);
printf("%s FOLDER\n",directoryname);
chdir(directoryname);
dp=opendir(directoryname);
if(dp==NULL)
{
printf("2\n");
}
strcat(temppath,dirhold);
listDir(dp,temppath);
}
else
{
snprintf(buf,99999,"%s",directoryname);
strcat(buf,"\\");
strcat(buf,file->d_name);
printf("%s FILE\n",buf);
}
}
}
This is my code that does more or less what you want. It is also available in my SOQ (Stack Overflow Questions) repository on GitHub as file dirlist43.c in the src/so-7406-2431 sub-directory.
What went wrong in the MCVE code?
There were a fairly large number of problems, including:
Not much error checking for failed calls.
Changing directory with changing back correctly.
No debug code to help determine what is going wrong.
Too many places where opendir() was called.
Too many places where the result of opendir() was checked — one of them in a different function from where the call was made.
Missing headers.
Unused variables.
Not reporting errors on stderr.
Confusion about directoryname vs temppath.
Sequencing of chdir() calls worked downwards, once. But there was no code to change back after finishing a directory.
Missing closedir() — I ran out of file descriptors when run on a directory with about 3000 sub-folders.
More debatable: I've used snprintf() or printf() to concatenate strings. For raw performance, you may find that strcpy() and strcat() are quicker, but using strcat() can slow things down as it scans from the start of the string each time. Clever code determines the length of the string so that you can copy each time you append, but the Standard C functions aren't helpful for that.
And notes from another comment:
Note that using chdir() is error prone — doubly so if there are symlinks lurking around — and should be avoided when possible. (This was an accurate comment.)
You have a large number of occurrences of 99999 (and some occurrences of 9999); there should be a macro (or enumeration constant) for that value.
On Unix systems, you must #include <errno.h> and should never declare extern int errno; because errno is typically not a simple variable but rather an expression that evaluates to a per-thread int value. I think the same is true on Windows.
Other solutions
In a comment, I noted that:
If you were coding on a Unix (POSIX) system, it would be an odds-on bet that the problem and the fixes are described in stat() error "no such file or directory when file name is returned by readdir(). Even on Windows, you are likely to be running into similar problems. However, there are Windows-specific APIs to process directories that could be used instead of readdir().
Since your MCVE code uses Windows-style \ path separators but compiles, the majority of the advice in that question is valid. Note that POSIX provides some functions — fstatat() and dirfd() — that avoid messing around with chdir(). This is advantageous, especially in threaded programs as chdir() changes directory for all threads at the same time, which is apt to cause chaos if the different threads are accessing files in different directories identified by relative rather than absolute pathnames.
Code: dirlist43.c
#include <dirent.h>
#include <errno.h>
#include <locale.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>
#ifdef UNIX
#define DIRSEP_STR "/"
#define DIRSEP_CHR '/'
#else
#define DIRSEP_STR "\\"
#define DIRSEP_CHR '\\'
#endif
#define PATH_LEN 99999
extern void listDir(const char *directoryname);
extern int isDir(const char *name);
int main(void)
{
setlocale(LC_ALL, "Turkish");
char pwd[PATH_LEN];
getcwd(pwd, sizeof(pwd));
printf("FOLDERMAIN: %s\n", pwd);
listDir(pwd);
return 0;
}
int isDir(const char *name)
{
struct stat fileStat;
int rc = stat(name, &fileStat) == 0 && S_ISDIR(fileStat.st_mode);
#ifdef DEBUG
printf("%s(): %d [%s]\n", __func__, rc, name);
#endif /* DEBUG */
return rc;
}
#ifdef DEBUG
static void chk_pwd(const char *tag)
{
char pwd[PATH_LEN];
if (getcwd(pwd, sizeof(pwd)) == 0)
{
int errnum = errno;
fprintf(stderr, "%s(): getcwd() failed: %d %s\n",
__func__, errnum, strerror(errnum));
exit(1);
}
printf("PWD: %s [%s]\n", tag, pwd);
}
#else
#define chk_pwd(tag) ((void)0)
#endif /* DEBUG */
static void set_pwd(const char *directoryname)
{
#ifdef DEBUG
printf("CHDIR 1: [%s]\n", directoryname);
#endif /* DEBUG */
if (chdir(directoryname) != 0)
{
int errnum = errno;
fprintf(stderr, "%s(): chdir(%s) failed: %d %s\n",
__func__, directoryname, errnum, strerror(errnum));
exit(1);
}
chk_pwd("CHDIR 1");
}
void listDir(const char *directoryname)
{
#ifdef DEBUG
static int level = 0;
#endif /* DEBUG */
static int check = 0;
#ifdef DEBUG
printf("-->> %s() level %d (%s)\n", __func__, ++level, directoryname);
#endif /* DEBUG */
DIR *dp = opendir(directoryname);
if (dp == NULL)
{
perror(directoryname);
return;
}
set_pwd(directoryname);
struct dirent *file;
while ((file = readdir(dp)) != NULL)
{
if (strcmp(file->d_name, "..") == 0 || (strcmp(file->d_name, ".") == 0))
continue;
if (isDir(file->d_name))
{
printf("CHECK: %d\n", ++check);
char temppath[PATH_LEN];
snprintf(temppath, sizeof(temppath), "%s%s%s",
directoryname, DIRSEP_STR, file->d_name);
printf("FOLDER: %s\n", temppath);
chk_pwd("Before recursion");
listDir(temppath);
set_pwd(directoryname);
chk_pwd("After recursion");
}
else
{
printf("FILE: %s%s%s\n", directoryname, DIRSEP_STR, file->d_name);
}
}
closedir(dp);
#ifdef DEBUG
printf("<<-- %s() level %d (%s)\n", __func__, level--, directoryname);
#endif /* DEBUG */
}
It can be compiled with -DUNIX if you work on a POSIX-like system where slash / is used to separate path components, or without if you work on a Windows-like system where backslash \ is used. It can be compiled with -DDEBUG to get copious extra debugging output.
The makefile is configured for Unix — the code was tested on a MacBook Pro running macOS Big Sur 11.7.
So I was doing some basic C then I'm blocked.
I wanted to count lines in a file. Function and prototype function are in .c (for the function) and in .h (for the prototype function), the problem is I get errors
Note : I use the compiler GNU GCC C++ 14 ISO
From Function.c :
#include "Functions.h"
int FileLineCount(FILE *file)
{
rewind(file);
int iCount = 0;
char string[MAX_CHARACTER_SIZE] = "";
while((fgets(string, MAX_CHARACTER_SIZE, file) != NULL))
{
iCount++;
}
return iCount;
}
From Function.h :
#ifndef __FUNCTIONS_INCLUDED__
#define __FONCTIONS_INCLUDED__
int FileLineCount(FILE *file);
#endif
From the main.c :
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "Functions.h"
#define MAX_CHARACTER_SIZE 256
int main()
{
FILE *WordsFile = NULL;
const char strWorldFileName[] = "RandomWords.txt";
WordsFile = fopen(strWorldFileName, "r");
if(WordsFile == NULL)
{
printf("Error ! Impossible to open the file %s\n", strWorldFileName);
printf("Verify if this .txt file is in the folder where the file main.c is in it\n");
return EXIT_FAILURE;
}
printf("Line count : %i\n\n", FileLineCount(WordsFile));
}
Here is the error from the compiler :
error: unknown type name 'FILE'
error: unknown type name 'FILE'
#include <stdio.h>
in your Functions.h file
and fix this to be the same 'functions' and 'fonctions'
#ifndef __FUNCTIONS_INCLUDED__
#define __FONCTIONS_INCLUDED__
I tried to compiler the following code(minimum example, see the edit for the whole code):
// a.c
#include <stdio.h>
#define _XOPEN_SOURCE
#include <unistd.h>
int main(int argc, char* argv[])
{
puts((const char*) crypt("AAAA", "$6$2222"));
return 0;
}
Using clang-7 -lcrypt a.c and it emitted the following warning:
minimum.c:8:24: warning: implicit declaration of function 'crypt' is invalid in C99 [-Wimplicit-function-declaration]
puts((const char*) crypt("AAAA", "$6$2222"));
^
minimum.c:8:10: warning: cast to 'const char *' from smaller integer type 'int' [-Wint-to-pointer-cast]
puts((const char*) crypt("AAAA", "$6$2222"));
^
2 warnings generated.
But ./a.out did seem to work:
$6$2222$6GKY4KPtBqD9jAhwxIZGDqEShaBaw.pkyJxjvSlKmtygDXKQ2Q62CPY98MPIZbz2h6iMCgLTVEYplzp.naYLz1
I found out that if I remove #include <stdio.h> and puts like this:
// new_a.c
#define _XOPEN_SOURCE
#include <unistd.h>
int main(int argc, char* argv[])
{
crypt("AAAA", "$6$2222");
return 0;
}
Then there is no warnings.
How to fix these warnings without removing #include <stdio.h>?
Edit:
Whole program:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define _X_OPEN_SOURCE
#include <unistd.h>
#include <assert.h>
void* Calloc(size_t cnt, size_t size)
{
void *ret = calloc(cnt, size);
assert(ret);
return ret;
}
size_t GetSaltLen(const char *salt)
{
size_t salt_len = strlen(salt);
assert(salt_len > 0);
assert(salt_len <= 16);
return salt_len;
}
char* GetSaltAndVersion(const char version, const char *salt)
{
size_t saltlen = GetSaltLen(salt);
/*
* The format of salt:
* $one_digit_number$up_to_16_character\0
* For more info, check man crypt.
*/
char *ret = (char*) Calloc(1 + 1 + 1 + saltlen + 1, sizeof(char));
char *beg = ret;
*beg++ = '$';
*beg++ = version;
*beg++ = '$';
memcpy((void*) beg, (const void*) salt, saltlen + 1);
return ret;
}
void crypt_and_print(const char *passwd, const char *salt_and_version)
{
char *result = crypt(passwd, salt_and_version);
assert(puts(result) != EOF);
}
int main(int argc, char* argv[])
{
if (argc != 4) {
fprintf(stderr, "argc = %d\n", argc);
return 1;
}
char *salt_and_version = GetSaltAndVersion(argv[2][0], argv[3]);
crypt_and_print(argv[1], salt_and_version);
free(salt_and_version);
return 0;
}
I have tried as #Andrey Akhmetov suggested and put the #define onto the first line, but the warnings did not disappear.
The macro _XOPEN_SOURCE is documented in feature_test_macros(7). In particular, the manpage states:
NOTE: In order to be effective, a feature test macro must be defined before including any header files. This can be done either in the compilation command (cc -DMACRO=value) or by defining the macro within the source code before including any headers.
When you include stdio.h, you indirectly include features.h, which uses the feature test macros as defined at that point. In particular, since _XOPEN_SOURCE and friends aren't defined at that point, crypt.h does not declare crypt.
By the time you define _XOPEN_SOURCE it is too late, since features.h has an include guard preventing it from being included twice.
By swapping the order of the first two lines, the code works without raising this warning on my system:
#define _XOPEN_SOURCE
#include <stdio.h>
#include <unistd.h>
int main(int argc, char* argv[])
{
puts((const char*) crypt("AAAA", "$6$2222"));
return 0;
}
Your larger example does not work for a second reason: You wrote _X_OPEN_SOURCE as the name of the macro, while the correct name is _XOPEN_SOURCE.
I defined a structure for options in my config file and a pointer to this structure in "config.h" file and I read config file using libconfig and set values in function get_config() that is defined in file "config.c". In main function I initialize pointer to structure and call get_config() function. libconfig works well and prints values of structure's fields correctly but when I print same fields in main functions their values are incorrect!
"config.h"
#include <stdio.h>
#include <stdlib.h>
#include <libconfig.h>
typedef struct
{
int buffer_size;
const char * DBusername;
const char * DBpassword;
}conf;
conf *config;
int get_config();
"config.c"
#include "config.h"
int get_config()
{
config_t cfg;
config_setting_t *setting;
config_init(&cfg);
/* Read the file. If there is an error, report it and exit. */
if(! config_read_file(&cfg, "config.cfg"))
{
fprintf(stderr, "%s:%d - %s\n", config_error_file(&cfg),
config_error_line(&cfg), config_error_text(&cfg));
config_destroy(&cfg);
return(EXIT_FAILURE);
}
if(config_lookup_int(&cfg, "buffersize", &config->buffer_size))
printf("buffersize: %d\n\n", config->buffer_size);
else
fprintf(stderr, "No 'buffersize' setting in configuration file.\n");
if(config_lookup_string(&cfg, "DBusername", &config->DBusername))
printf("DBusername: %s\n\n", config->DBusername);
else
fprintf(stderr, "No 'DBusername' setting in configuration file.\n");
if(config_lookup_string(&cfg, "DBpassword", &config->DBpassword))
printf("DBpassword: %s\n\n", config->DBpassword);
else
fprintf(stderr, "No 'DBpassword' setting in configuration file.\n");
config_destroy(&cfg);
return(EXIT_SUCCESS);
}
"store.c"
int main(){
config = (conf*) malloc(sizeof(conf));
if(get_config() == EXIT_FAILURE)
return 0;
printf("\n%s", config->DBusername);
printf("\n%s", config->DBpassword);
printf("\n%d", config->buffer_size);
}
The problem is because of defining char* in structure. I changed the char* to char[] and the problem is solved! :)
I defined a structure for options in my config file and a pointer to this structure in "config.h" file...
That statement makes me wonder what a config file is. i.e. is it a .c, or a .h? And what is the visibility to it for other files?
Your issue is likely because the scope (visibilty) of the structure is not provided to the file in which the main() function resides. #include the .h where the struct is defined, and make sure an instantiation of that struct either has global scope, or create an instantiation inside main()
This configuration of files will provide visibility to to main of a struct defined in the .h:
in somefile.h:
typedef struct
{
int membername;
} A_STRUCT;
extern A_STRUCT a
;
in someotherFile.c
#include "somefile.h"
A_STRUCT a = {3}; //global copy of the struct, with assignment
int main(void)
{
printf("%d", a.membername);
return 0;
}
This is part of a program where I call a function that reads components from a ".dat" file and save the input to members of a Struct. When I try calling the function from my main.c it gives various errors depending on what I try. Most notably: conflicting types of 'ReadFile' and too few arguments to function 'ReadFile'. I also get a warning "passing argument from 'ReadFile' makes integer from pointer without cast" and some infos.
This is main.c
#include "MyData.h"
#include "NodalA.h"
#include "FileHandling.h"
#include <stdio.h>
#include "windows.h"
int main(){
ComponentType *CircuitData;
int numComp = 6;
int numEl = 0;
int numNodes = 0;
CircuitData = malloc((numComp)*sizeof(ComponentType));
ReadFile(CircuitData, &numEl, &numNodes);
return 0;
}
This is FileHandling.c:
#include "FileHandling.h"
#include "stdio.h"
void ReadFile(ComponentType *CircuitData, int *numEl, int *numNodes){
numEl = 0;
numNodes = 0;
int index = 0;
FILE *data;
data = fopen("mydata.dat", "r");
if (data == NULL){
printf("Error: \"mydata.dat\" could not be opened");
}
else {
while(!feof(data)){
fscanf(data, "%s, %s, %s, %f", CircuitData[index].name, CircuitData[index].node1, CircuitData[index].node2, CircuitData[index].value);
*CircuitData[index].node1 = extractInteger(CircuitData[index].node1);
*CircuitData[index].node2 = extractInteger(CircuitData[index].node2);
if(*CircuitData[index].node1 > *numNodes)
*numNodes = *CircuitData[index].node1;
if(*CircuitData[index].node2 > *numNodes)
*numNodes = *CircuitData[index].node2;
numEl++;
index++;
}
}
fclose(data);
}
And this is MyData.h
#ifndef MYDATA_H_
#define MYDATA_H_
typedef struct Comp{
char name[5]; //Name of circuit component
char node1[5], node2[5]; //2 nodes
float value[5]; //value
}ComponentType;
#endif /* MYDATA_H_ */
Any help would be appreciated. There are more code but I think this is the most important part.
The ReadFile function name used in the program is the same as a ReadFile function in "windows.h". The error "too few arguments to function 'ReadFile'" is most likely caused by the program trying to call the the function from windows with the wrong arguments. Removing "windows.h" or renaming the function ReadFile to something else solves the problem.