I am trying to write a program that implements somehow the "dir" command that you can use in the Unix shell but I have encountered the following problem. I managed to read the current directory as I will show in the code but I don't know exactly how I am supposed to sort it in order to make it like the dir function which sorts the files from the directory
#include <stdio.h>
#include <string.h>
#include <dirent.h>
#include <stdlib.h>
#include <string.h>
void dirfunction()
{
DIR* directory=opendir(".");
if(directory==NULL)
{
perror("Directory does not exist");
exit(1);
}
struct dirent* p;
p=readdir(directory);
int i=0;
while(p!=NULL)
{
if(strcmp(p->d_name,".")!=0 && strcmp(p->d_name,"..")!=0)
{
printf("%s ",p->d_name);
i ;
}
p=readdir(directory);
}
printf("\n");
closedir(directory);
}
int main(int argc,char** argv[])
{
dirfunction();
}
Should I basically do the normal sorting for an array of character, like adding all file names in an array of string and sort it with selection sort or another sort method? I don't really get how dir command sorts the files before printing them to the terminal.
CodePudding user response:
Because readdir
reuses the same buffer for the returned entry, we need a dynamic [growing] array to save/store the struct dirent
entries.
Then, we need to sort the stored entries (e.g. use qsort
).
Side note: int main(int argc,char **argv[])
is incorrect. It should be: int main(int argc,char **argv)
There was one too many levels of indirection.
Below is the updated code with some enhancements. It is annotated:
#include <stdio.h>
#include <string.h>
#include <dirent.h>
#include <stdlib.h>
#include <string.h>
// dynamic array of dirent structs
struct dirlist {
size_t count; // number of entries
struct dirent *base; // pointer to list start
};
// dirload -- load up directory
// RETURNS: directory list
struct dirlist *
dirload(const char *path)
{
size_t capacity = 0;
struct dirlist *list = calloc(1,sizeof(*list));
DIR *directory = opendir(path);
if (directory == NULL) {
perror("Directory does not exist");
exit(1);
}
struct dirent *p;
while (1) {
// get next entry
// this is overwritten, so we need to copy/save it below
p = readdir(directory);
if (p == NULL)
break;
// skip over "." and ".."
if (p->d_name[0] == '.') {
if (p->d_name[1] == 0)
continue;
if ((p->d_name[1] == '.') && (p->d_name[2] == 0))
continue;
}
// enlarge array
if (list->count >= capacity) {
capacity = 10;
list->base = realloc(list->base,sizeof(*list->base) * capacity);
if (list->base == NULL) {
perror("realloc");
exit(1);
}
}
// save dirent entry
list->base[list->count ] = *p;
}
closedir(directory);
// trim list to actual size
list->base = realloc(list->base,sizeof(*list->base) * list->count);
if (list->base == NULL) {
perror("realloc");
exit(1);
}
return list;
}
// dircmp -- compare dirent structs
int
dircmp(const void *lhsp,const void *rhsp)
{
const struct dirent *lhs = lhsp;
const struct dirent *rhs = rhsp;
int cmp;
cmp = strcmp(lhs->d_name,rhs->d_name);
return cmp;
}
// dirsort -- sort directory list
void
dirsort(struct dirlist *list)
{
if (list->count > 0)
qsort(list->base,list->count,sizeof(*list->base),dircmp);
}
// dirprint -- print directory list
void
dirprint(const struct dirlist *list)
{
const struct dirent *p = list->base;
for (size_t idx = 0; idx < list->count; idx, p)
printf("%s\n",p->d_name);
}
// dirdestroy -- destroy directory list
void
dirdestroy(struct dirlist *list)
{
if (list != NULL)
free(list->base);
free(list);
}
int
main(int argc, char **argv)
{
--argc;
argv;
const char *dir;
if (argc > 0)
dir = *argv;
else
dir = ".";
struct dirlist *list = dirload(dir);
// sort the list
dirsort(list);
// print the list
dirprint(list);
// destroy the list
dirdestroy(list);
return 0;
}