Reputation: 6655
I'm new to C programming. I made a very short program to merge all the files in a folder. The program runs and produces the right output, but after execution it hangs and I have to manually kill it. Any ideas why?
The important functions here are scandir
and append_to_file
/*
MERGE: Merges text files. Gives the ability to merge a list of files or all files in a
directory with specified extension.
*/
#include <stdio.h>
#include <dirent.h>
#include <stdbool.h>
#include <string.h>
#include <stdlib.h>
/* Function prototypes */
int append_to_file(const char *filename, const char *outfilename); // Appends the contents of filename to outfilename
int scandir(char dirname[], char const *ext, char outfile[]); // Scans a directory for files of a specific extension and merges them
bool has_extension(char const *name, char const *ext);
void usage(); // Prints out usage information (help) to the console
void path_combine(char *dest, const char *path1, const char *path2); // Combines a directory name and filename to a single filepath
int main(int argc, char *argv[])
{
int i, // Counters
nfiles; // Number of files merged
if (argc == 4)
{
nfiles = scandir(argv[1], argv[2], argv[3]);
printf("Merged %s files\n", nfiles);
return 0;
}
else
{
printf("Wrong input, quitting");
return 1;
}
}
int append_to_file(const char *filename, const char *outfilename)
{
FILE *infile, *outfile;
char ch;
infile = fopen(filename, "r");
outfile = fopen(outfilename, "a");
if (infile == NULL)
{
printf("Input file is empty, skipping...\n");
return 1;
}
while ((ch = fgetc(infile)) != EOF)
fputc(ch, outfile);
fclose(infile);
fclose(outfile);
return 0;
}
int scandir(char dirname[], char const *ext, char outfile[])
/* Scans a directory and merges all files of given extension */
{
DIR *d = NULL;
struct dirent *dir = NULL;
char filepath[strlen(dirname) + 255];
int i = 0;
d = opendir(dirname);
if (d)
{
while ((dir = readdir(d)) != NULL)
{
if (has_extension(dir->d_name, ext))
{
path_combine(filepath, dirname, dir->d_name);
printf("%s\n", filepath);
append_to_file(filepath, outfile);
i++;
}
}
closedir(d);
}
return i;
}
bool has_extension(char const *name, char const *ext)
{
size_t len = strlen(name);
return len > 4 && strcmp(name+len-4, ext) == 0;
}
void path_combine(char *dest, const char *path1, const char *path2)
{
const char *last_char = path1;
int append_sep = 0;
char sep[] = "/";
#ifdef WIN32
sep[0] = '\\';
#endif
/* Find the last character in the first path*/
while(*last_char != '\0')
last_char++;
/* If the last character is not a seperator, we must add it*/
if (strcmp(last_char, sep) !=0)
{
append_sep = 1;
}
strcpy(dest, path1);
if (append_sep)
strcat(dest, sep);
strcat(dest, path2);
}
void usage()
{
printf("\t=================\n");
printf("\t MERGE\n");
printf("\t=================\n");
printf("Merge two or more text files\n");
printf("Usage:\n");
printf("\tCall merge with a directory name and desired extension:\n");
printf("\tmerge DIRNAME .csv OUTPUTFILE\n\n");
};
Upvotes: 0
Views: 5763
Reputation: 6655
Ah.
I thought I was using the debugger, by specifying -g
when compiling:
gcc main.c -g -o main.exe
But it was still hanging.
If I included the flags -Wall
and -Werror
it soon told me that I had a string formatting error.
the line printf("Merged %s files\n", nfiles)
needed to be changed to printf("Merged %d files\n", nfiles)
.
Compiling with -Wall and -Werror soon pointed out this mistake.
Upvotes: -1
Reputation: 1
As the compiler warned you (if you compile with gcc -Wall -g
), the following line:
printf("Merged %s files\n", nfiles);
is wrong, since nfiles
is an int
. You probably want
printf("Merged %d files\n", nfiles);
Read about undefined behavior. You've got one. Read also carefully the documentation of every function you are using, starting with printf(3) & fopen(3) & perror(3) & exit(3). Don't forget to handle failure, e.g:
FILE *infile, *outfile;
char ch;
infile = fopen(filename, "r");
outfile = fopen(outfilename, "a");
if (infile == NULL) {
printf("failed to open %s (%s), skipping...\n",
filename, strerror(errno));
return 1;
}
if (outfile == NULL) {
perror(outfilename);
exit(EXIT_FAILURE);
}
Learn how to use your debugger (gdb
). If on Linux, use also strace(1) and valgrind.
Upvotes: 3