Complete rewrite
This commit is contained in:
parent
1692350a0b
commit
e059ec80c7
482
src/ls.c
482
src/ls.c
|
@ -2,159 +2,395 @@
|
|||
|
||||
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
extern int optind;
|
||||
#include <dirent.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
|
||||
/* types */
|
||||
typedef struct _Prefs {
|
||||
int C;
|
||||
int F;
|
||||
int R;
|
||||
int a;
|
||||
int c;
|
||||
int d;
|
||||
int i;
|
||||
int l;
|
||||
int q;
|
||||
int r;
|
||||
int t;
|
||||
int u;
|
||||
} Prefs;
|
||||
/* FIXME */
|
||||
#define max(a, b) ((a) > (b) ? (a) : (b))
|
||||
|
||||
/* Prefs */
|
||||
typedef int Prefs;
|
||||
#define PREFS_a 1
|
||||
|
||||
/* ls */
|
||||
static int _ls_is_directory(char * filename);
|
||||
static int _ls_directory(char * filename, Prefs * p);
|
||||
static int _ls_file(char * filename, Prefs * p);
|
||||
static int _ls(int argc, char * argv[], Prefs * p)
|
||||
{
|
||||
int res = 0;
|
||||
int i;
|
||||
|
||||
if(argc == 0)
|
||||
return _ls_directory(".", p) != 0 ? 2 : 0;
|
||||
for(i = 0; i < argc; i++)
|
||||
{
|
||||
if(i != 0)
|
||||
printf("\n");
|
||||
if(_ls_is_directory(argv[i]))
|
||||
{
|
||||
if(argc != 1)
|
||||
printf("%s:\n", argv[i]);
|
||||
if(_ls_directory(argv[i], p) != 0)
|
||||
res = 2;
|
||||
continue;
|
||||
}
|
||||
if(_ls_file(argv[i], p) != 0)
|
||||
res = 2;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
static int _ls_is_directory(char * filename)
|
||||
{
|
||||
struct stat buf;
|
||||
|
||||
if(stat(filename, &buf) == -1 || !S_ISDIR(buf.st_mode))
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _ls_directory(char * filename, Prefs * p)
|
||||
{
|
||||
DIR * dir;
|
||||
struct dirent * dirent;
|
||||
|
||||
if((dir = opendir(filename)) == NULL)
|
||||
{
|
||||
fprintf(stderr, "%s", "ls: ");
|
||||
perror(filename);
|
||||
return 1;
|
||||
}
|
||||
while((dirent = readdir(dir)) != NULL)
|
||||
{
|
||||
if(dirent->d_name[0] == '.' && p->a == 0)
|
||||
continue;
|
||||
printf("%s\n", dirent->d_name);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _ls_file(char * filename, Prefs * p)
|
||||
{
|
||||
struct stat buf;
|
||||
|
||||
if(stat(filename, &buf) == -1)
|
||||
{
|
||||
fprintf(stderr, "%s", "ls: ");
|
||||
perror(filename);
|
||||
return 1;
|
||||
}
|
||||
printf("%s", filename);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* prefs_parse */
|
||||
static int _prefs_parse(int argc, char * argv[], Prefs * p)
|
||||
static int _usage(void);
|
||||
static int _prefs_parse(Prefs * prefs, int argc, char * argv[])
|
||||
{
|
||||
int o;
|
||||
|
||||
memset(p, 0, sizeof(Prefs));
|
||||
while((o = getopt(argc, argv, "CFRacdilqrtu1HL")) != -1)
|
||||
/* memset(prefs, 0, sizeof(Prefs)); */
|
||||
*prefs = 0;
|
||||
while((o = getopt(argc, argv, "CFRa")) != -1)
|
||||
{
|
||||
switch(o)
|
||||
{
|
||||
case 'C':
|
||||
p->C = 1;
|
||||
break;
|
||||
case 'F':
|
||||
p->F = 1;
|
||||
break;
|
||||
case 'R':
|
||||
p->R = 1;
|
||||
break;
|
||||
fprintf(stderr, "%s%c%s", "ls: -", o,
|
||||
": not yet implemented");
|
||||
return _usage();
|
||||
case 'a':
|
||||
p->a = 1;
|
||||
break;
|
||||
case 'l':
|
||||
p->l = 1;
|
||||
break;
|
||||
case 'q':
|
||||
p->q = 1;
|
||||
break;
|
||||
case 'r':
|
||||
p->r = 1;
|
||||
break;
|
||||
case 't':
|
||||
p->t = 1;
|
||||
break;
|
||||
case 'u':
|
||||
p->u = 1;
|
||||
*prefs &= PREFS_a;
|
||||
break;
|
||||
case '?':
|
||||
return 1;
|
||||
return _usage();
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* SList */
|
||||
/* SListCell */
|
||||
typedef struct _SListCell {
|
||||
void * data;
|
||||
struct _SListCell * next;
|
||||
} SListCell;
|
||||
typedef SListCell * SList;
|
||||
|
||||
static SListCell * _slistcell_new(void * data, SListCell * next)
|
||||
{
|
||||
SListCell * slc;
|
||||
|
||||
if((slc = malloc(sizeof(SListCell))) == NULL)
|
||||
return NULL;
|
||||
slc->data = data;
|
||||
slc->next = next;
|
||||
return slc;
|
||||
}
|
||||
|
||||
static void _slistcell_delete(SListCell * slistcell)
|
||||
{
|
||||
free(slistcell);
|
||||
}
|
||||
|
||||
static SList * slist_new(void)
|
||||
{
|
||||
SList * sl;
|
||||
|
||||
if((sl = malloc(sizeof(SList))) == NULL)
|
||||
return NULL;
|
||||
*sl = NULL;
|
||||
return sl;
|
||||
}
|
||||
|
||||
static void slist_delete(SList * slist)
|
||||
{
|
||||
SListCell * slc = *slist;
|
||||
SListCell * p;
|
||||
|
||||
while(slc != NULL)
|
||||
{
|
||||
p = slc->next;
|
||||
_slistcell_delete(slc);
|
||||
slc = p;
|
||||
}
|
||||
free(slist);
|
||||
}
|
||||
|
||||
/* returns */
|
||||
static void * slist_data(SList * slist)
|
||||
{
|
||||
if(*slist == NULL)
|
||||
return NULL;
|
||||
return (*slist)->data;
|
||||
}
|
||||
|
||||
static void slist_next(SList * slist)
|
||||
{
|
||||
if(*slist == NULL)
|
||||
return;
|
||||
*slist = (*slist)->next;
|
||||
}
|
||||
|
||||
static void slist_last(SList * slist)
|
||||
{
|
||||
if(*slist == NULL)
|
||||
return;
|
||||
while((*slist)->next != NULL)
|
||||
*slist = (*slist)->next;
|
||||
}
|
||||
|
||||
static int slist_append(SList * slist, void * data)
|
||||
{
|
||||
slist_last(slist);
|
||||
if(*slist == NULL)
|
||||
{
|
||||
*slist = _slistcell_new(data, NULL);
|
||||
return *slist != NULL ? 0 : 2;
|
||||
}
|
||||
(*slist)->next = _slistcell_new(data, NULL);
|
||||
return (*slist)->next != NULL ? 0 : 2;
|
||||
}
|
||||
|
||||
static void slist_apply(SList * slist, int (*func)(void *, void *), void * user)
|
||||
{
|
||||
SListCell * slc = *slist;
|
||||
|
||||
while(slc != NULL)
|
||||
{
|
||||
func(slc->data, user);
|
||||
slc = slc->next;
|
||||
}
|
||||
}
|
||||
|
||||
static int slist_insert_sorted(SList * slist, void * data,
|
||||
int (*func)(void *, void *))
|
||||
{
|
||||
SListCell * slc = *slist;
|
||||
SListCell * p = NULL;
|
||||
|
||||
while(slc != NULL && func(slc->data, data) < 0)
|
||||
{
|
||||
p = slc;
|
||||
slc = slc->next;
|
||||
}
|
||||
if(slc == NULL) /* empty or last */
|
||||
{
|
||||
if((slc = _slistcell_new(data, NULL)) == NULL)
|
||||
return 1;
|
||||
if(p == NULL)
|
||||
*slist = slc; /* empty */
|
||||
else
|
||||
p->next = slc; /* last */
|
||||
return 0;
|
||||
}
|
||||
if((p = _slistcell_new(slc->data, slc->next)) == NULL)
|
||||
return 1;
|
||||
slc->data = data;
|
||||
slc->next = p;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static size_t slist_length(SList * slist)
|
||||
{
|
||||
SListCell * slc = *slist;
|
||||
size_t len;
|
||||
|
||||
for(len = 0; slc != NULL; len++)
|
||||
slc = slc->next;
|
||||
return len;
|
||||
}
|
||||
|
||||
|
||||
/* ls */
|
||||
static int _ls_do(SList * files, SList * dirs, Prefs * prefs);
|
||||
static int _ls(int argc, char * argv[], Prefs * prefs)
|
||||
{
|
||||
char * dircur = ".";
|
||||
int i;
|
||||
struct stat st;
|
||||
SList * files;
|
||||
SList * dirs;
|
||||
int res;
|
||||
|
||||
if(argc == 0)
|
||||
return _ls(1, &dircur, prefs);
|
||||
if((files = slist_new()) == NULL)
|
||||
return 1;
|
||||
if((dirs = slist_new()) == NULL)
|
||||
{
|
||||
slist_delete(files);
|
||||
return 1;
|
||||
}
|
||||
for(i = 0; i < argc; i++)
|
||||
{
|
||||
if(stat(argv[i], &st) != 0)
|
||||
{
|
||||
fprintf(stderr, "%s", "ls: ");
|
||||
perror(argv[i]);
|
||||
continue;
|
||||
}
|
||||
if(S_ISDIR(st.st_mode) == 0)
|
||||
slist_insert_sorted(files, argv[i], strcmp);
|
||||
else
|
||||
slist_append(dirs, argv[i]);
|
||||
}
|
||||
res = _ls_do(files, dirs, prefs);
|
||||
slist_delete(files);
|
||||
slist_delete(dirs);
|
||||
return res;
|
||||
}
|
||||
|
||||
static int _ls_files(SList * files, Prefs * prefs);
|
||||
static int _ls_directories(SList * dirs, Prefs * prefs);
|
||||
static int _ls_do(SList * files, SList * dirs, Prefs * prefs)
|
||||
{
|
||||
_ls_files(files, prefs);
|
||||
if(slist_data(files) != NULL && slist_data(dirs) != NULL)
|
||||
printf("%s%s%s", "\n", (char*)slist_data(dirs), ":\n");
|
||||
else if(slist_length(dirs) > 1)
|
||||
printf("%s%s", (char*)slist_data(dirs), ":\n");
|
||||
_ls_directories(dirs, prefs);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _ls_files(SList * files, Prefs * prefs)
|
||||
{
|
||||
char * cols;
|
||||
char * p;
|
||||
unsigned int len = 0;
|
||||
unsigned int lenmax = 0;
|
||||
unsigned int colnb = 0;
|
||||
unsigned int i = 0;
|
||||
unsigned int j = 0;
|
||||
SList cur = *files;
|
||||
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "%s", "_ls_files()\n");
|
||||
#endif
|
||||
if((cols = getenv("COLUMNS")) != NULL
|
||||
&& *cols != '\0'
|
||||
&& (len = strtol(cols, &p, 10)) > 0
|
||||
&& *p == '\0')
|
||||
{
|
||||
while(cur != NULL)
|
||||
{
|
||||
lenmax = max(lenmax, strlen(slist_data(&cur)));
|
||||
slist_next(&cur);
|
||||
}
|
||||
if(lenmax > 0)
|
||||
colnb = len / ++lenmax;
|
||||
}
|
||||
for(cur = *files; cur != NULL; slist_next(&cur))
|
||||
{
|
||||
printf("%s", (char*)slist_data(&cur));
|
||||
if(++i < colnb)
|
||||
{
|
||||
for(j = strlen(slist_data(&cur)); j < lenmax; j++)
|
||||
fputc(' ', stdout);
|
||||
continue;
|
||||
}
|
||||
fputc('\n', stdout);
|
||||
i = 0;
|
||||
}
|
||||
if(i != 0)
|
||||
fputc('\n', stdout);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _ls_directory(char * filename, Prefs * prefs);
|
||||
static int _ls_directories(SList * directories, Prefs * prefs)
|
||||
{
|
||||
SList sl = *directories;
|
||||
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "%s", "_ls_directories()\n");
|
||||
#endif
|
||||
if(sl == NULL)
|
||||
return 0;
|
||||
_ls_directory((char*)slist_data(&sl), prefs);
|
||||
slist_next(&sl);
|
||||
while(sl != NULL)
|
||||
{
|
||||
printf("%s%s%s", "\n", (char*)slist_data(&sl), ":\n");
|
||||
_ls_directory(slist_data(&sl), prefs);
|
||||
slist_next(&sl);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _ls_directory_do(char * filename, DIR * dir, SList * files,
|
||||
Prefs * prefs);
|
||||
static int _ls_directory(char * filename, Prefs * prefs)
|
||||
{
|
||||
DIR * dir;
|
||||
SList * files;
|
||||
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "%s%s%s", "_ls_directory(", filename, ")\n");
|
||||
#endif
|
||||
if((dir = opendir(filename)) == NULL)
|
||||
{
|
||||
fprintf(stderr, "%s", "ls: ");
|
||||
perror(filename);
|
||||
return 2;
|
||||
}
|
||||
if((files = slist_new()) == NULL)
|
||||
{
|
||||
closedir(dir);
|
||||
return 1;
|
||||
}
|
||||
_ls_directory_do(filename, dir, files, prefs);
|
||||
slist_delete(files);
|
||||
closedir(dir);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _ls_free(char * filename, void * null);
|
||||
static int _ls_directory_do(char * filename, DIR * dir, SList * files,
|
||||
Prefs * prefs)
|
||||
{
|
||||
char * str = NULL;
|
||||
unsigned int len;
|
||||
struct dirent * dirent;
|
||||
struct stat st;
|
||||
char * p;
|
||||
|
||||
len = strlen(filename);
|
||||
if((str = strdup(filename)) == NULL)
|
||||
{
|
||||
fprintf(stderr, "%s", "ls: ");
|
||||
perror("strdup");
|
||||
return 2;
|
||||
}
|
||||
while((dirent = readdir(dir)) != NULL)
|
||||
{
|
||||
if((p = realloc(str, len + strlen(dirent->d_name)
|
||||
+ 2)) == NULL)
|
||||
{
|
||||
fprintf(stderr, "%s", "ls: ");
|
||||
perror("realloc");
|
||||
break;
|
||||
}
|
||||
str = p;
|
||||
str[len] = '/';
|
||||
str[len+1] = '\0';
|
||||
strcat(str, dirent->d_name);
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "stat(%s)\n", str);
|
||||
#endif
|
||||
if(stat(str, &st) == -1)
|
||||
{
|
||||
fprintf(stderr, "%s", "ls: ");
|
||||
perror(dirent->d_name);
|
||||
continue;
|
||||
}
|
||||
if((*prefs & PREFS_a) == 0 && *(dirent->d_name) == '.')
|
||||
continue;
|
||||
if((p = strdup(dirent->d_name)) == NULL)
|
||||
{
|
||||
fprintf(stderr, "%s", "ls: ");
|
||||
perror("strdup");
|
||||
continue;
|
||||
}
|
||||
slist_insert_sorted(files, p, strcmp);
|
||||
}
|
||||
free(str);
|
||||
_ls_files(files, prefs);
|
||||
slist_apply(files, _ls_free, prefs);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _ls_free(char * filename, void * null)
|
||||
{
|
||||
free(filename);
|
||||
return 0;
|
||||
null = null;
|
||||
}
|
||||
|
||||
|
||||
/* usage */
|
||||
static int _usage(void)
|
||||
{
|
||||
fprintf(stderr, "%s", "Usage: ls [-CFRacdilqrtu1][-H|-L][-fgmnopsx]\n\
|
||||
-R recursively list subdirectories\n\
|
||||
-a write out all directory entries\n\
|
||||
-c use time of last modification of the files status\n\
|
||||
-l write out as long format\n\
|
||||
-L evaluate referenced files for symlinks\n");
|
||||
fprintf(stderr, "%s", "Usage: ls [-CFRa]\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -164,7 +400,7 @@ int main(int argc, char * argv[])
|
|||
{
|
||||
Prefs p;
|
||||
|
||||
if(_prefs_parse(argc, argv, &p) == 1)
|
||||
if(_prefs_parse(&p, argc, argv) != 0)
|
||||
return _usage();
|
||||
return _ls(argc - optind, &argv[optind], &p);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user