/* let's compile using: gcc main.c -Wall -Wextra --pedantic --std=c2x -D_GNU_SOURCE -Ofast -march=corei7 -mtune=corei7 */
/* Linux headers begin */
#include <dirent.h>
#include <sys/stat.h>
#include <unistd.h>
/* Linux headers end */
#include <stdlib.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#define ALLOCATION_ATTEMPT_LIMIT 4
#define SUCCESS 0
#define FAIL -1
char * concat_file_path(const char * directory, const char * file_name)
{
const char * separator = "/";
char * result = NULL;
size_t directory_length = strlen(directory);
size_t file_name_length = strlen(file_name);
size_t separator_length = strlen(separator);
char count = 0;
while (((result = malloc(sizeof(char) * (directory_length + separator_length + file_name_length + 1))) == NULL) && (++count < ALLOCATION_ATTEMPT_LIMIT))
sleep(1);
if (result == NULL)
{
perror("Error: memory allocation failed.");
exit(EXIT_FAILURE);
}
memcpy(result, directory, directory_length);
memcpy(result + directory_length, separator, separator_length);
memcpy(result + directory_length + separator_length, file_name, file_name_length + 1);
return result;
}
void close_directory(DIR * directory_pointer)
{
if (closedir(directory_pointer) == 0)
{
puts("Directory was closed.");
}
else
perror("Error: closing directory failed.");
}
DIR * open_directory(const char * directory_path)
{
DIR * directory_pointer = opendir(directory_path);
if (directory_pointer == NULL)
{
perror("Error: directory stream is NULL.");
exit(EXIT_FAILURE);
}
return directory_pointer;
}
char check_for_non_ascii(FILE * text_file_pointer)
{
char current = fgetc (text_file_pointer);
if (current == EOF)
return FAIL;
do
{
if (isascii(current) == 0)
return FAIL;
}
while ((current = fgetc (text_file_pointer)) != EOF);
return SUCCESS;
}
void remove_if_non_us_ascii(char * full_path)
{
FILE * text_file_pointer = fopen(full_path, "r");
if (text_file_pointer == NULL)
{
perror("Error: file opening error.");
exit(EXIT_FAILURE);
}
if (check_for_non_ascii(text_file_pointer) == 0)
{
fclose(text_file_pointer);
if (remove(full_path) == 0)
{
puts("File removed.");
}
else
{
printf("Occured an error on removing a file on the path: %s", full_path);
}
}
else
fclose(text_file_pointer);
}
void perform_if_regular_file(DIR * directory_pointer, char * full_path)
{
struct stat stat_buffer;
if (lstat(full_path, &stat_buffer) == 0)
{
if ((stat_buffer.st_mode & S_IFMT) == S_IFREG)
{
remove_if_non_us_ascii(full_path);
}
}
else
{
perror("Error: getting file information failed.");
close_directory(directory_pointer);
exit(EXIT_FAILURE);
}
}
void main_loop(DIR * directory_pointer, const char * directory_path)
{
struct dirent * directory_entry_struct = NULL;
char * full_path = NULL;
while ((directory_entry_struct = readdir (directory_pointer)) != NULL)
{
full_path = concat_file_path(directory_path, directory_entry_struct->d_name);
perform_if_regular_file(directory_pointer, full_path);
}
}
int main (void)
{
const char * directory_path = ".";
DIR * directory_pointer = open_directory(directory_path);
errno = 0;
main_loop(directory_pointer, directory_path);
if (errno != 0)
{
perror("Error: reading directory entry failed.");
close_directory(directory_pointer);
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
I am new to C. Please, give an advice on reliability of program, programming style and performance. You have to put program executable into a folder containing text files in any encoding on Linux machine. After running it you could have only US ASCII text files in the folder. I have tested this code on a 11 GiB storage.