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 <sys/stat.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
extern int optind;
|
extern int optind;
|
||||||
#include <dirent.h>
|
#include <dirent.h>
|
||||||
|
#include <stdlib.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
|
||||||
/* types */
|
/* FIXME */
|
||||||
typedef struct _Prefs {
|
#define max(a, b) ((a) > (b) ? (a) : (b))
|
||||||
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;
|
|
||||||
|
|
||||||
|
/* Prefs */
|
||||||
|
typedef int Prefs;
|
||||||
|
#define PREFS_a 1
|
||||||
|
|
||||||
/* ls */
|
static int _usage(void);
|
||||||
static int _ls_is_directory(char * filename);
|
static int _prefs_parse(Prefs * prefs, int argc, char * argv[])
|
||||||
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)
|
|
||||||
{
|
{
|
||||||
int o;
|
int o;
|
||||||
|
|
||||||
memset(p, 0, sizeof(Prefs));
|
/* memset(prefs, 0, sizeof(Prefs)); */
|
||||||
while((o = getopt(argc, argv, "CFRacdilqrtu1HL")) != -1)
|
*prefs = 0;
|
||||||
|
while((o = getopt(argc, argv, "CFRa")) != -1)
|
||||||
{
|
{
|
||||||
switch(o)
|
switch(o)
|
||||||
{
|
{
|
||||||
case 'C':
|
case 'C':
|
||||||
p->C = 1;
|
|
||||||
break;
|
|
||||||
case 'F':
|
case 'F':
|
||||||
p->F = 1;
|
|
||||||
break;
|
|
||||||
case 'R':
|
case 'R':
|
||||||
p->R = 1;
|
fprintf(stderr, "%s%c%s", "ls: -", o,
|
||||||
break;
|
": not yet implemented");
|
||||||
|
return _usage();
|
||||||
case 'a':
|
case 'a':
|
||||||
p->a = 1;
|
*prefs &= PREFS_a;
|
||||||
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;
|
|
||||||
break;
|
break;
|
||||||
case '?':
|
case '?':
|
||||||
return 1;
|
return _usage();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
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 */
|
/* usage */
|
||||||
static int _usage(void)
|
static int _usage(void)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "%s", "Usage: ls [-CFRacdilqrtu1][-H|-L][-fgmnopsx]\n\
|
fprintf(stderr, "%s", "Usage: ls [-CFRa]\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");
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -164,7 +400,7 @@ int main(int argc, char * argv[])
|
||||||
{
|
{
|
||||||
Prefs p;
|
Prefs p;
|
||||||
|
|
||||||
if(_prefs_parse(argc, argv, &p) == 1)
|
if(_prefs_parse(&p, argc, argv) != 0)
|
||||||
return _usage();
|
return _usage();
|
||||||
return _ls(argc - optind, &argv[optind], &p);
|
return _ls(argc - optind, &argv[optind], &p);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user