From b738680464fd2d381b49ffc091308541b5b5b229 Mon Sep 17 00:00:00 2001 From: Sigmanificient Date: Fri, 19 Apr 2024 20:56:39 +0200 Subject: [PATCH 01/10] Add basic ls implementation --- src/ls/Makefile | 6 ++- src/ls/list_directories.c | 107 ++++++++++++++++++++++++++++++++++++++ src/ls/ls.c | 6 --- src/ls/ls.h | 65 +++++++++++++++++++++++ src/ls/main.c | 68 ++++++++++++++++++++++++ src/ls/print_info.c | 105 +++++++++++++++++++++++++++++++++++++ src/ls/recursive_walk.c | 59 +++++++++++++++++++++ src/ls/sort_entries.c | 26 +++++++++ src/ls/strdup.c | 14 +++++ 9 files changed, 449 insertions(+), 7 deletions(-) create mode 100644 src/ls/list_directories.c delete mode 100644 src/ls/ls.c create mode 100644 src/ls/ls.h create mode 100644 src/ls/main.c create mode 100644 src/ls/print_info.c create mode 100644 src/ls/recursive_walk.c create mode 100644 src/ls/sort_entries.c create mode 100644 src/ls/strdup.c diff --git a/src/ls/Makefile b/src/ls/Makefile index 411fc95..4c12572 100644 --- a/src/ls/Makefile +++ b/src/ls/Makefile @@ -1,5 +1,9 @@ OUT := ls -SRC := ls.c +SRC := main.c +SRC += list_directories.c +SRC += print_info.c +SRC += recursive_walk.c +SRC += sort_entries.c include ../shared.mk diff --git a/src/ls/list_directories.c b/src/ls/list_directories.c new file mode 100644 index 0000000..69769fc --- /dev/null +++ b/src/ls/list_directories.c @@ -0,0 +1,107 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ls.h" + +static +void get_file_info(const char *path, entry_t *entry) +{ + if (stat(path, &entry->stat) < 0) + return; + entry->passwd = getpwuid(entry->stat.st_uid); + entry->group = getgrgid(entry->stat.st_gid); +} + +static +int read_directory(dirbuff_t *db, DIR *dir, char flags) +{ + static char path[PATH_MAX]; + int i = 0; + + if (dir == NULL) + return -1; + for (struct dirent *dirent = readdir(dir); dirent; dirent = readdir(dir)) { + if (dirent->d_name[0] == '.' && ~flags & F_ALL_FILES) + continue; + if (i == db->size) { + db->size <<= 1; + db->entries = realloc( + db->entries, db->size * sizeof(*db->entries)); + } + strcpy(db->entries[i].name, dirent->d_name); + if (flags & (F_LONG_FORM | F_SORT_TIME | F_RECURSIVE)) + get_file_info(path_concat(path, db->name, db->entries[i].name), + &db->entries[i]); + i++; + } + return i; +} + +static +void print_error(char *dirname) +{ + switch (errno) { + case ENOENT: + fprintf(stderr, + "ls: cannot access '%s': No such file or directory\n", + dirname); + return; + case EACCES: + fprintf(stderr, + "ls: cannot open directory '%s': Permission denied\n", + dirname); + return; + default: + fprintf(stderr, "Unknown error\n"); + } +} + +static +int read_arg(dirbuff_t *db, char flags) +{ + struct stat fi; + int count = 1; + DIR *dir; + + db->is_file = 0; + if (stat(db->name, &fi) < 0) { + print_error(db->name); + return -1; + } + if (S_ISDIR(fi.st_mode) && ~flags & F_DIRECTORY) { + dir = opendir(db->name); + count = read_directory(db, dir, flags); + closedir(dir); + } else { + strcpy(db->entries[0].name, db->name); + get_file_info(db->name, &db->entries[0]); + db->is_file = 1; + } + return count; +} + +int list_dir(dirbuff_t *db, char flags) +{ + int count = read_arg(db, flags); + + if (count == -1) + return -1; + sort_entries(db->entries, count); + if (flags & F_SORT_TIME) + sort_entries_by_time(db->entries, count); + if (flags & (F_SHOW_DIRS | F_RECURSIVE) && !db->is_file) + printf("%s:\n", db->name); + print_entries(db->entries, count, flags); + if (flags & F_RECURSIVE && !db->is_file) + recurse(db, count, flags); + return 0; +} diff --git a/src/ls/ls.c b/src/ls/ls.c deleted file mode 100644 index 6e6d777..0000000 --- a/src/ls/ls.c +++ /dev/null @@ -1,6 +0,0 @@ -#include - -int main(void) { - printf("Hello, World!\n"); - return 0; -} \ No newline at end of file diff --git a/src/ls/ls.h b/src/ls/ls.h new file mode 100644 index 0000000..d8a3df4 --- /dev/null +++ b/src/ls/ls.h @@ -0,0 +1,65 @@ +#ifndef MY_LS_H + #define MY_LS_H + + #include + + #define ZERO_OR(expr, default) ((!!(expr)) * default) + +#define __USE_XOPEN2K8 +#define __USE_MISC + + #include + #include + + #define MIN_ALLOCATED_ENTRY (1024) + +enum { + EXIT_OK = 0, + EXIT_KO = 84 +}; + +enum { + F_ALL_FILES = 1 << 0, + F_LONG_FORM = 1 << 1, + F_RECURSIVE = 1 << 2, + F_DIRECTORY = 1 << 3, + F_REV_ORDER = 1 << 4, + F_SORT_TIME = 1 << 5, + F_SHOW_DIRS = 1 << 6, +}; + +typedef struct { + struct stat stat; + struct passwd *passwd; + struct group *group; + char name[NAME_MAX + 1]; +} entry_t; + +typedef struct { + char *name; + entry_t *entries; + int size; + int is_file; +} dirbuff_t; + +inline +int stridx(const char *str, char c) +{ + for (const char *p = str; *p != '\0'; p++) + if (*p == c) + return p - str; + return -1; +} + +char *strdup(char const *s); + +int list_dir(dirbuff_t *db, char flags); +int recurse(dirbuff_t *db, int count, char flags); + +void print_entries(entry_t *entry, int count, char flags); +char *path_concat(char *dest, char *basepath, char *suffix); + +void sort_entries(entry_t *entries, int count); +void sort_entries_by_time(entry_t *entries, int count); + +#endif diff --git a/src/ls/main.c b/src/ls/main.c new file mode 100644 index 0000000..66a8516 --- /dev/null +++ b/src/ls/main.c @@ -0,0 +1,68 @@ +#include + +#include "ls.h" + +static const char *FLAGLIST = "alRdrt"; +static char DEFAULT_LOCATION[2] = "."; + +static +char compose_flaglist(int argc, char **argv) +{ + int flags = 0; + + for (int i = 1; i < argc; i++) { + if (argv[i][0] != '-' || argv[i][1] == '\0') + continue; + for (int j = 1; argv[i][j] != '\0'; j++) + flags |= 1 << (stridx(FLAGLIST, argv[i][j]) + 1); + } + return (char)(flags >> 1); +} + +static +int count_targets(int argc, char **argv) +{ + int count = 0; + + for (int i = 1; i < argc; i++) + if (argv[i][0] != '-' || argv[i][1] == '\0') + count++; + return count; +} + +static +int list_dirs(dirbuff_t *db, int argc, char **argv, char flags) +{ + int err = 0; + int count = count_targets(argc, argv); + + if (count == 0) { + db->name = DEFAULT_LOCATION; + err |= list_dir(db, flags); + } + for (int i = 1; i < argc; i++) { + if (argv[i][0] == '-' && argv[i][1] != '\0') + continue; + db->name = argv[i]; + if (count > 1) + flags |= F_SHOW_DIRS; + err |= list_dir(db, flags); + } + return err; +} + +int main(int argc, char **argv) +{ + dirbuff_t db = { .size = MIN_ALLOCATED_ENTRY }; + char flags = compose_flaglist(argc, argv); + int err = 0; + + db.entries = malloc(db.size * sizeof(*db.entries)); + if (db.entries == NULL) + return EXIT_KO; + if (flags & F_DIRECTORY) + flags &= ~F_RECURSIVE; + err |= list_dirs(&db, argc, argv, flags); + free(db.entries); + return err ? EXIT_KO : EXIT_OK; +} diff --git a/src/ls/print_info.c b/src/ls/print_info.c new file mode 100644 index 0000000..d85cccd --- /dev/null +++ b/src/ls/print_info.c @@ -0,0 +1,105 @@ +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "ls.h" + +static +void get_file_right(char bits[], entry_t *entry) +{ + mode_t mode = entry->stat.st_mode; + static const char *s = "-rwx"; + + bits[0] = s[(unsigned char)ZERO_OR(mode & S_IRUSR, 1)]; + bits[1] = s[(unsigned char)ZERO_OR(mode & S_IWUSR, 2)]; + bits[2] = s[(unsigned char)ZERO_OR(mode & S_IXUSR, 3)]; + bits[3] = s[(unsigned char)ZERO_OR(mode & S_IRGRP, 1)]; + bits[4] = s[(unsigned char)ZERO_OR(mode & S_IWGRP, 2)]; + bits[5] = s[(unsigned char)ZERO_OR(mode & S_IXGRP, 3)]; + bits[6] = s[(unsigned char)ZERO_OR(mode & S_IROTH, 1)]; + bits[7] = s[(unsigned char)ZERO_OR(mode & S_IWOTH, 2)]; + bits[8] = s[(unsigned char)ZERO_OR(mode & S_IXOTH, 3)]; + if (mode & S_ISUID) + bits[1] = (mode & S_IXUSR) ? 's' : 'S'; + if (mode & S_ISGID) + bits[3] = (mode & S_IXGRP) ? 's' : 'l'; + if (mode & S_ISVTX) + bits[8] = (mode & S_IXOTH) ? 't' : 'T'; +} + +static +char get_file_type(entry_t *entry) +{ + const char typ[] = { + [ S_IFBLK ] = 'b', + [ S_IFCHR ] = 'c', + [ S_IFDIR ] = 'd', + [ S_IFIFO ] = 'p', + [ S_IFLNK ] = 'l', + [ S_IFREG ] = '-', + [ S_IFSOCK ] = 's', + [ 0 ] = '?' + }; + + return typ[(entry->stat.st_mode & S_IFMT)]; +} + +static +char *get_creation_time(entry_t *entry) +{ + static char fmt[12]; + char *ct = ctime(&entry->stat.st_mtim.tv_sec); + time_t now = time(NULL); + const int six_month_sec = 6 * 24 * 3600 * 31; + + if (entry->stat.st_mtim.tv_sec + six_month_sec < now) { + strncpy(fmt, ct + 4, 7); + strncpy(fmt + 7, ct + 19, 5); + } else + strncpy(fmt, ct + 4, 12); + return fmt; +} + +static +void print_file_infos(entry_t *entry) +{ + struct stat *fi = &entry->stat; + char perms[10] = { [0] = get_file_type(entry) }; + const char *owner = (entry->passwd == NULL) ? "?" : entry->passwd->pw_name; + const char *grp = (entry->group == NULL) ? "?" : entry->group->gr_name; + char *time = get_creation_time(entry); + + get_file_right(perms + 1, entry); + printf("%.10s %ld %s %s ", perms, fi->st_nlink, owner, grp); + if (stridx("bc", perms[0]) != -1) + printf("%d, %d", major(fi->st_rdev), minor(fi->st_rdev)); + else + printf("%ld", fi->st_size); + printf(" %.12s ", time); +} + +void print_entries(entry_t *entry, int count, char flags) +{ + int d; + + if (flags & F_REV_ORDER) { + d = -1; + entry += (count - 1); + } else + d = 1; + for (int i = 0; i < count; i++) { + if (flags & F_LONG_FORM) + print_file_infos(entry); + printf("%s", entry->name); + printf(((i + 1) == count || flags & F_LONG_FORM) ? "\n" : " "); + entry += d; + } +} diff --git a/src/ls/recursive_walk.c b/src/ls/recursive_walk.c new file mode 100644 index 0000000..154764f --- /dev/null +++ b/src/ls/recursive_walk.c @@ -0,0 +1,59 @@ +#include +#include + +#include "ls.h" + +char *path_concat(char *dest, char *basepath, char *suffix) +{ + int written = 0; + + strcpy(dest, basepath); + written = strlen(basepath); + if (dest[written - 1] != '/') { + dest[written] = '/'; + written++; + } + strcpy(dest + written, suffix); + written += strlen(suffix); + dest[written] = '\0'; + return dest; +} + +static +int find_directories(char **dirs, dirbuff_t *db, int count) +{ + int found = 0; + + if (dirs == NULL) + return -1; + for (int i = 0; i < count; i++) { + if (!strcmp(db->entries[i].name, ".") + || !strcmp(db->entries[i].name, "..")) + continue; + if (S_ISDIR(db->entries[i].stat.st_mode)) { + dirs[found] = strdup(db->entries[i].name); + found++; + } + } + return found; +} + +int recurse(dirbuff_t *db, int count, char flags) +{ + static char path[PATH_MAX]; + int dirsize = strlen(db->name); + char **dirs = malloc(count * sizeof(char *)); + int j = find_directories(dirs, db, count); + + if (j == -1) + return -1; + for (int i = 0; i < j; i++) { + db->name = path_concat(path, db->name, dirs[i]); + list_dir(db, flags); + db->name[dirsize] = '\0'; + } + for (int i = 0; i < j; i++) + free(dirs[i]); + free(dirs); + return 0; +} diff --git a/src/ls/sort_entries.c b/src/ls/sort_entries.c new file mode 100644 index 0000000..c96247d --- /dev/null +++ b/src/ls/sort_entries.c @@ -0,0 +1,26 @@ +#include +#include + +#include "ls.h" + +static +int compare_names(entry_t const *leftp, entry_t const *rightp) +{ + return strcoll(leftp->name, rightp->name); +} + +static +int compare_times(entry_t const *leftp, entry_t const *rightp) +{ + return rightp->stat.st_mtim.tv_sec - leftp->stat.st_mtim.tv_sec; +} + +void sort_entries(entry_t *entries, int count) +{ + qsort(entries, count, sizeof(*entries), (__compar_fn_t)&compare_names); +} + +void sort_entries_by_time(entry_t *entries, int count) +{ + qsort(entries, count, sizeof(*entries), (__compar_fn_t)&compare_times); +} diff --git a/src/ls/strdup.c b/src/ls/strdup.c new file mode 100644 index 0000000..13fc67a --- /dev/null +++ b/src/ls/strdup.c @@ -0,0 +1,14 @@ +#include +#include + +#include "ls.h" + +char *strdup(char const *s) +{ + int len = strlen(s); + char *dupped = malloc(len + 1); + + strcpy(dupped, s); + dupped[len] = '\0'; + return dupped; +} From d064dd58cf7bb466b5695f10e9fa28a1f22bfd9b Mon Sep 17 00:00:00 2001 From: Sigmanificient Date: Fri, 19 Apr 2024 21:08:06 +0200 Subject: [PATCH 02/10] Add simple man --- src/ls/ls.1 | 40 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 39 insertions(+), 1 deletion(-) diff --git a/src/ls/ls.1 b/src/ls/ls.1 index fca0bf6..9611ddf 100644 --- a/src/ls/ls.1 +++ b/src/ls/ls.1 @@ -1 +1,39 @@ -\" TODO \ No newline at end of file +.Dt %N 1 +.Dd April 19, 2024 +.Dt ls 1 +.Os +.Sh NAME +.Nm ls +.Nd list directory contents (Canoutils implementation) +.Sh SYNOPSIS +.Nm +.Op Fl h +.TP +. +.Sh DESCRIPTION +.Nm +List information about the FILEs (the current directory by default). +. +.Sh OPTIONS +\fBls\fR interprets the following options when it is invoked: +.Pp +.Bl -tag -width Ds +. +.It Fl a +do not ignore entries starting with `.` +.It Fl l +use a long listing format +.It Fl R +list subdirectories recursively +.It Fl d +list directories themselves, not their contents +.It Fl r +reverse order while sorting +.It Fl t +sort by time, newest first +. +.El +. +.Sh AUTHOR +Canoutils `ls` was written by \fBSigmanificient\fB. +.br From 61066c5c3e87d91d845d335f07d575176248e828 Mon Sep 17 00:00:00 2001 From: Sigmanificient Date: Fri, 19 Apr 2024 21:11:24 +0200 Subject: [PATCH 03/10] Feature minor code improvements --- src/ls/ls.h | 5 ----- src/ls/main.c | 4 ++-- src/ls/print_info.c | 19 ++++++++++--------- 3 files changed, 12 insertions(+), 16 deletions(-) diff --git a/src/ls/ls.h b/src/ls/ls.h index d8a3df4..6ae17fe 100644 --- a/src/ls/ls.h +++ b/src/ls/ls.h @@ -13,11 +13,6 @@ #define MIN_ALLOCATED_ENTRY (1024) -enum { - EXIT_OK = 0, - EXIT_KO = 84 -}; - enum { F_ALL_FILES = 1 << 0, F_LONG_FORM = 1 << 1, diff --git a/src/ls/main.c b/src/ls/main.c index 66a8516..f1cc724 100644 --- a/src/ls/main.c +++ b/src/ls/main.c @@ -59,10 +59,10 @@ int main(int argc, char **argv) db.entries = malloc(db.size * sizeof(*db.entries)); if (db.entries == NULL) - return EXIT_KO; + return EXIT_FAILURE; if (flags & F_DIRECTORY) flags &= ~F_RECURSIVE; err |= list_dirs(&db, argc, argv, flags); free(db.entries); - return err ? EXIT_KO : EXIT_OK; + return err ? EXIT_SUCCESS : EXIT_FAILURE; } diff --git a/src/ls/print_info.c b/src/ls/print_info.c index d85cccd..060ff5e 100644 --- a/src/ls/print_info.c +++ b/src/ls/print_info.c @@ -15,18 +15,19 @@ static void get_file_right(char bits[], entry_t *entry) { + char *bitsp = bits; mode_t mode = entry->stat.st_mode; static const char *s = "-rwx"; - bits[0] = s[(unsigned char)ZERO_OR(mode & S_IRUSR, 1)]; - bits[1] = s[(unsigned char)ZERO_OR(mode & S_IWUSR, 2)]; - bits[2] = s[(unsigned char)ZERO_OR(mode & S_IXUSR, 3)]; - bits[3] = s[(unsigned char)ZERO_OR(mode & S_IRGRP, 1)]; - bits[4] = s[(unsigned char)ZERO_OR(mode & S_IWGRP, 2)]; - bits[5] = s[(unsigned char)ZERO_OR(mode & S_IXGRP, 3)]; - bits[6] = s[(unsigned char)ZERO_OR(mode & S_IROTH, 1)]; - bits[7] = s[(unsigned char)ZERO_OR(mode & S_IWOTH, 2)]; - bits[8] = s[(unsigned char)ZERO_OR(mode & S_IXOTH, 3)]; + *bitsp++ = s[(unsigned char)ZERO_OR(mode & S_IRUSR, 1)]; + *bitsp++ = s[(unsigned char)ZERO_OR(mode & S_IWUSR, 2)]; + *bitsp++ = s[(unsigned char)ZERO_OR(mode & S_IXUSR, 3)]; + *bitsp++ = s[(unsigned char)ZERO_OR(mode & S_IRGRP, 1)]; + *bitsp++ = s[(unsigned char)ZERO_OR(mode & S_IWGRP, 2)]; + *bitsp++ = s[(unsigned char)ZERO_OR(mode & S_IXGRP, 3)]; + *bitsp++ = s[(unsigned char)ZERO_OR(mode & S_IROTH, 1)]; + *bitsp++ = s[(unsigned char)ZERO_OR(mode & S_IWOTH, 2)]; + *bitsp++ = s[(unsigned char)ZERO_OR(mode & S_IXOTH, 3)]; if (mode & S_ISUID) bits[1] = (mode & S_IXUSR) ? 's' : 'S'; if (mode & S_ISGID) From 95fedcd454e3ce545f1390e0214e61690a1a3a04 Mon Sep 17 00:00:00 2001 From: Sigmanificient Date: Fri, 19 Apr 2024 21:29:34 +0200 Subject: [PATCH 04/10] Improve overall types --- src/ls/Makefile | 1 - src/ls/list_directories.c | 52 ++++++++++++++++++++------------------- src/ls/ls.h | 16 ++++++------ src/ls/main.c | 12 ++++----- src/ls/print_info.c | 36 +++++++++++++++------------ src/ls/recursive_walk.c | 24 ++++++++---------- src/ls/sort_entries.c | 26 -------------------- src/ls/strdup.c | 2 +- 8 files changed, 71 insertions(+), 98 deletions(-) delete mode 100644 src/ls/sort_entries.c diff --git a/src/ls/Makefile b/src/ls/Makefile index 4c12572..7eb0f83 100644 --- a/src/ls/Makefile +++ b/src/ls/Makefile @@ -4,6 +4,5 @@ SRC := main.c SRC += list_directories.c SRC += print_info.c SRC += recursive_walk.c -SRC += sort_entries.c include ../shared.mk diff --git a/src/ls/list_directories.c b/src/ls/list_directories.c index 69769fc..6a245a3 100644 --- a/src/ls/list_directories.c +++ b/src/ls/list_directories.c @@ -6,7 +6,6 @@ #include #include #include -#include #include #include @@ -21,14 +20,12 @@ void get_file_info(const char *path, entry_t *entry) entry->group = getgrgid(entry->stat.st_gid); } -static -int read_directory(dirbuff_t *db, DIR *dir, char flags) +static __attribute__((nonnull)) +size_t read_directory(dirbuff_t *db, DIR *dir, char flags) { static char path[PATH_MAX]; - int i = 0; + size_t i = 0; - if (dir == NULL) - return -1; for (struct dirent *dirent = readdir(dir); dirent; dirent = readdir(dir)) { if (dirent->d_name[0] == '.' && ~flags & F_ALL_FILES) continue; @@ -66,38 +63,43 @@ void print_error(char *dirname) } static -int read_arg(dirbuff_t *db, char flags) +int compare_names(entry_t const *leftp, entry_t const *rightp) +{ + return strcoll(leftp->name, rightp->name); +} + +static +int compare_times(entry_t const *leftp, entry_t const *rightp) +{ + return (int)( + rightp->stat.st_mtim.tv_sec + - leftp->stat.st_mtim.tv_sec + ); +} + +int list_dir(dirbuff_t *db, char flags) { struct stat fi; - int count = 1; + size_t count = 1; DIR *dir; - db->is_file = 0; - if (stat(db->name, &fi) < 0) { - print_error(db->name); - return -1; - } - if (S_ISDIR(fi.st_mode) && ~flags & F_DIRECTORY) { + if (stat(db->name, &fi) < 0) + return print_error(db->name), -1; + db->is_file = S_ISDIR(fi.st_mode) && ~flags & F_DIRECTORY; + if (db->is_file) { dir = opendir(db->name); count = read_directory(db, dir, flags); closedir(dir); } else { strcpy(db->entries[0].name, db->name); get_file_info(db->name, &db->entries[0]); - db->is_file = 1; } - return count; -} - -int list_dir(dirbuff_t *db, char flags) -{ - int count = read_arg(db, flags); - if (count == -1) - return -1; - sort_entries(db->entries, count); + qsort(db->entries, count, + sizeof *db->entries, (__compar_fn_t)&compare_names); if (flags & F_SORT_TIME) - sort_entries_by_time(db->entries, count); + qsort(db->entries, count, + sizeof *db->entries, (__compar_fn_t)&compare_times); if (flags & (F_SHOW_DIRS | F_RECURSIVE) && !db->is_file) printf("%s:\n", db->name); print_entries(db->entries, count, flags); diff --git a/src/ls/ls.h b/src/ls/ls.h index 6ae17fe..8a97628 100644 --- a/src/ls/ls.h +++ b/src/ls/ls.h @@ -1,6 +1,7 @@ #ifndef MY_LS_H #define MY_LS_H + #include #include #define ZERO_OR(expr, default) ((!!(expr)) * default) @@ -33,28 +34,25 @@ typedef struct { typedef struct { char *name; entry_t *entries; - int size; - int is_file; + size_t size; + bool is_file; } dirbuff_t; -inline +inline __attribute__((const)) int stridx(const char *str, char c) { for (const char *p = str; *p != '\0'; p++) if (*p == c) - return p - str; + return (int)(p - str); return -1; } char *strdup(char const *s); int list_dir(dirbuff_t *db, char flags); -int recurse(dirbuff_t *db, int count, char flags); +size_t recurse(dirbuff_t *db, size_t count, char flags); -void print_entries(entry_t *entry, int count, char flags); +void print_entries(entry_t *entry, size_t count, char flags); char *path_concat(char *dest, char *basepath, char *suffix); -void sort_entries(entry_t *entries, int count); -void sort_entries_by_time(entry_t *entries, int count); - #endif diff --git a/src/ls/main.c b/src/ls/main.c index f1cc724..2320a42 100644 --- a/src/ls/main.c +++ b/src/ls/main.c @@ -2,8 +2,8 @@ #include "ls.h" -static const char *FLAGLIST = "alRdrt"; -static char DEFAULT_LOCATION[2] = "."; +static const char FLAGLIST[] = "alRdrt"; +static char DEFAULT_LOCATION[] = "."; static char compose_flaglist(int argc, char **argv) @@ -20,7 +20,7 @@ char compose_flaglist(int argc, char **argv) } static -int count_targets(int argc, char **argv) +size_t count_targets(int argc, char **argv) { int count = 0; @@ -31,10 +31,10 @@ int count_targets(int argc, char **argv) } static -int list_dirs(dirbuff_t *db, int argc, char **argv, char flags) +bool list_dirs(dirbuff_t *db, int argc, char **argv, char flags) { int err = 0; - int count = count_targets(argc, argv); + size_t count = count_targets(argc, argv); if (count == 0) { db->name = DEFAULT_LOCATION; @@ -62,7 +62,7 @@ int main(int argc, char **argv) return EXIT_FAILURE; if (flags & F_DIRECTORY) flags &= ~F_RECURSIVE; - err |= list_dirs(&db, argc, argv, flags); + err |= !list_dirs(&db, argc, argv, flags); free(db.entries); return err ? EXIT_SUCCESS : EXIT_FAILURE; } diff --git a/src/ls/print_info.c b/src/ls/print_info.c index 060ff5e..05e970b 100644 --- a/src/ls/print_info.c +++ b/src/ls/print_info.c @@ -12,22 +12,24 @@ #include "ls.h" +typedef unsigned char uchar; + static -void get_file_right(char bits[], entry_t *entry) +void get_file_right(char bits[static sizeof("rwxrwxrwx")], entry_t *entry) { char *bitsp = bits; mode_t mode = entry->stat.st_mode; static const char *s = "-rwx"; - *bitsp++ = s[(unsigned char)ZERO_OR(mode & S_IRUSR, 1)]; - *bitsp++ = s[(unsigned char)ZERO_OR(mode & S_IWUSR, 2)]; - *bitsp++ = s[(unsigned char)ZERO_OR(mode & S_IXUSR, 3)]; - *bitsp++ = s[(unsigned char)ZERO_OR(mode & S_IRGRP, 1)]; - *bitsp++ = s[(unsigned char)ZERO_OR(mode & S_IWGRP, 2)]; - *bitsp++ = s[(unsigned char)ZERO_OR(mode & S_IXGRP, 3)]; - *bitsp++ = s[(unsigned char)ZERO_OR(mode & S_IROTH, 1)]; - *bitsp++ = s[(unsigned char)ZERO_OR(mode & S_IWOTH, 2)]; - *bitsp++ = s[(unsigned char)ZERO_OR(mode & S_IXOTH, 3)]; + *bitsp++ = s[(uchar)ZERO_OR(mode & S_IRUSR, 1)]; + *bitsp++ = s[(uchar)ZERO_OR(mode & S_IWUSR, 2)]; + *bitsp++ = s[(uchar)ZERO_OR(mode & S_IXUSR, 3)]; + *bitsp++ = s[(uchar)ZERO_OR(mode & S_IRGRP, 1)]; + *bitsp++ = s[(uchar)ZERO_OR(mode & S_IWGRP, 2)]; + *bitsp++ = s[(uchar)ZERO_OR(mode & S_IXGRP, 3)]; + *bitsp++ = s[(uchar)ZERO_OR(mode & S_IROTH, 1)]; + *bitsp++ = s[(uchar)ZERO_OR(mode & S_IWOTH, 2)]; + *bitsp++ = s[(uchar)ZERO_OR(mode & S_IXOTH, 3)]; if (mode & S_ISUID) bits[1] = (mode & S_IXUSR) ? 's' : 'S'; if (mode & S_ISGID) @@ -56,11 +58,13 @@ char get_file_type(entry_t *entry) static char *get_creation_time(entry_t *entry) { - static char fmt[12]; + static char fmt[sizeof("Jan 01 00:00")]; char *ct = ctime(&entry->stat.st_mtim.tv_sec); time_t now = time(NULL); const int six_month_sec = 6 * 24 * 3600 * 31; + if (strlen(ct) < 24) + return NULL; if (entry->stat.st_mtim.tv_sec + six_month_sec < now) { strncpy(fmt, ct + 4, 7); strncpy(fmt + 7, ct + 19, 5); @@ -73,9 +77,9 @@ static void print_file_infos(entry_t *entry) { struct stat *fi = &entry->stat; - char perms[10] = { [0] = get_file_type(entry) }; - const char *owner = (entry->passwd == NULL) ? "?" : entry->passwd->pw_name; - const char *grp = (entry->group == NULL) ? "?" : entry->group->gr_name; + char perms[sizeof("-rwxr-xr-x")] = { [0] = get_file_type(entry), '\0' }; + char const *owner = (entry->passwd == NULL) ? "?" : entry->passwd->pw_name; + char const *grp = (entry->group == NULL) ? "?" : entry->group->gr_name; char *time = get_creation_time(entry); get_file_right(perms + 1, entry); @@ -87,7 +91,7 @@ void print_file_infos(entry_t *entry) printf(" %.12s ", time); } -void print_entries(entry_t *entry, int count, char flags) +void print_entries(entry_t *entry, size_t count, char flags) { int d; @@ -96,7 +100,7 @@ void print_entries(entry_t *entry, int count, char flags) entry += (count - 1); } else d = 1; - for (int i = 0; i < count; i++) { + for (size_t i = 0; i < count; i++) { if (flags & F_LONG_FORM) print_file_infos(entry); printf("%s", entry->name); diff --git a/src/ls/recursive_walk.c b/src/ls/recursive_walk.c index 154764f..916a8c3 100644 --- a/src/ls/recursive_walk.c +++ b/src/ls/recursive_walk.c @@ -5,7 +5,7 @@ char *path_concat(char *dest, char *basepath, char *suffix) { - int written = 0; + unsigned long written = 0; strcpy(dest, basepath); written = strlen(basepath); @@ -19,14 +19,12 @@ char *path_concat(char *dest, char *basepath, char *suffix) return dest; } -static -int find_directories(char **dirs, dirbuff_t *db, int count) +static __attribute__((nonnull)) +size_t find_directories(char **dirs, dirbuff_t *db, size_t count) { - int found = 0; + size_t found = 0; - if (dirs == NULL) - return -1; - for (int i = 0; i < count; i++) { + for (size_t i = 0; i < count; i++) { if (!strcmp(db->entries[i].name, ".") || !strcmp(db->entries[i].name, "..")) continue; @@ -38,21 +36,19 @@ int find_directories(char **dirs, dirbuff_t *db, int count) return found; } -int recurse(dirbuff_t *db, int count, char flags) +size_t recurse(dirbuff_t *db, size_t count, char flags) { static char path[PATH_MAX]; - int dirsize = strlen(db->name); + size_t dirsize = strlen(db->name); char **dirs = malloc(count * sizeof(char *)); - int j = find_directories(dirs, db, count); + size_t j = find_directories(dirs, db, count); - if (j == -1) - return -1; - for (int i = 0; i < j; i++) { + for (size_t i = 0; i < j; i++) { db->name = path_concat(path, db->name, dirs[i]); list_dir(db, flags); db->name[dirsize] = '\0'; } - for (int i = 0; i < j; i++) + for (size_t i = 0; i < j; i++) free(dirs[i]); free(dirs); return 0; diff --git a/src/ls/sort_entries.c b/src/ls/sort_entries.c deleted file mode 100644 index c96247d..0000000 --- a/src/ls/sort_entries.c +++ /dev/null @@ -1,26 +0,0 @@ -#include -#include - -#include "ls.h" - -static -int compare_names(entry_t const *leftp, entry_t const *rightp) -{ - return strcoll(leftp->name, rightp->name); -} - -static -int compare_times(entry_t const *leftp, entry_t const *rightp) -{ - return rightp->stat.st_mtim.tv_sec - leftp->stat.st_mtim.tv_sec; -} - -void sort_entries(entry_t *entries, int count) -{ - qsort(entries, count, sizeof(*entries), (__compar_fn_t)&compare_names); -} - -void sort_entries_by_time(entry_t *entries, int count) -{ - qsort(entries, count, sizeof(*entries), (__compar_fn_t)&compare_times); -} diff --git a/src/ls/strdup.c b/src/ls/strdup.c index 13fc67a..12d056b 100644 --- a/src/ls/strdup.c +++ b/src/ls/strdup.c @@ -5,7 +5,7 @@ char *strdup(char const *s) { - int len = strlen(s); + size_t len = strlen(s); char *dupped = malloc(len + 1); strcpy(dupped, s); From b8e511478698806badfcccaea0bef892ecb9698d Mon Sep 17 00:00:00 2001 From: Sigmanificient Date: Fri, 19 Apr 2024 21:59:12 +0200 Subject: [PATCH 05/10] Prefix source with `ls_` to avoid vpath collisions --- src/ls/Makefile | 8 ++++---- src/ls/{list_directories.c => ls_list_directories.c} | 0 src/ls/{main.c => ls_main.c} | 0 src/ls/{print_info.c => ls_print_info.c} | 0 src/ls/{recursive_walk.c => ls_recursive_walk.c} | 0 src/ls/{strdup.c => ls_strdup.c} | 0 6 files changed, 4 insertions(+), 4 deletions(-) rename src/ls/{list_directories.c => ls_list_directories.c} (100%) rename src/ls/{main.c => ls_main.c} (100%) rename src/ls/{print_info.c => ls_print_info.c} (100%) rename src/ls/{recursive_walk.c => ls_recursive_walk.c} (100%) rename src/ls/{strdup.c => ls_strdup.c} (100%) diff --git a/src/ls/Makefile b/src/ls/Makefile index 7eb0f83..b0065b9 100644 --- a/src/ls/Makefile +++ b/src/ls/Makefile @@ -1,8 +1,8 @@ OUT := ls -SRC := main.c -SRC += list_directories.c -SRC += print_info.c -SRC += recursive_walk.c +SRC := ls_main.c +SRC += ls_list_directories.c +SRC += ls_print_info.c +SRC += ls_recursive_walk.c include ../shared.mk diff --git a/src/ls/list_directories.c b/src/ls/ls_list_directories.c similarity index 100% rename from src/ls/list_directories.c rename to src/ls/ls_list_directories.c diff --git a/src/ls/main.c b/src/ls/ls_main.c similarity index 100% rename from src/ls/main.c rename to src/ls/ls_main.c diff --git a/src/ls/print_info.c b/src/ls/ls_print_info.c similarity index 100% rename from src/ls/print_info.c rename to src/ls/ls_print_info.c diff --git a/src/ls/recursive_walk.c b/src/ls/ls_recursive_walk.c similarity index 100% rename from src/ls/recursive_walk.c rename to src/ls/ls_recursive_walk.c diff --git a/src/ls/strdup.c b/src/ls/ls_strdup.c similarity index 100% rename from src/ls/strdup.c rename to src/ls/ls_strdup.c From f9d29280a6db2f4e427d7a2d16b6d0d68d6a2c2f Mon Sep 17 00:00:00 2001 From: Sigmanificient Date: Fri, 19 Apr 2024 23:34:46 +0200 Subject: [PATCH 06/10] Use strerror and wrap __attribute__ --- src/ls/ls.h | 4 ++++ src/ls/ls_list_directories.c | 12 +++++++----- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/src/ls/ls.h b/src/ls/ls.h index 8a97628..3496e20 100644 --- a/src/ls/ls.h +++ b/src/ls/ls.h @@ -14,6 +14,10 @@ #define MIN_ALLOCATED_ENTRY (1024) + #if !defined(__clang__) || !defined (__GNUC__) + #define __attribute__(x) // omitted + #endif + enum { F_ALL_FILES = 1 << 0, F_LONG_FORM = 1 << 1, diff --git a/src/ls/ls_list_directories.c b/src/ls/ls_list_directories.c index 6a245a3..f135796 100644 --- a/src/ls/ls_list_directories.c +++ b/src/ls/ls_list_directories.c @@ -46,19 +46,21 @@ size_t read_directory(dirbuff_t *db, DIR *dir, char flags) static void print_error(char *dirname) { + char const *err = strerror(errno); + switch (errno) { case ENOENT: fprintf(stderr, - "ls: cannot access '%s': No such file or directory\n", - dirname); + "ls: cannot access '%s': %s\n", + dirname, err); return; case EACCES: fprintf(stderr, - "ls: cannot open directory '%s': Permission denied\n", - dirname); + "ls: cannot open directory '%s': %s\n", + dirname, err); return; default: - fprintf(stderr, "Unknown error\n"); + fprintf(stderr, "ls: %s\n", err); } } From 36b1d6296050404ad1d724c345fc78fc80d58cca Mon Sep 17 00:00:00 2001 From: Sigmanificient Date: Fri, 19 Apr 2024 23:41:32 +0200 Subject: [PATCH 07/10] Add missing opendir check --- src/ls/ls_list_directories.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/ls/ls_list_directories.c b/src/ls/ls_list_directories.c index f135796..225a430 100644 --- a/src/ls/ls_list_directories.c +++ b/src/ls/ls_list_directories.c @@ -26,7 +26,11 @@ size_t read_directory(dirbuff_t *db, DIR *dir, char flags) static char path[PATH_MAX]; size_t i = 0; - for (struct dirent *dirent = readdir(dir); dirent; dirent = readdir(dir)) { + for ( + struct dirent *dirent = readdir(dir); + dirent != NULL; + dirent = readdir(dir) + ) { if (dirent->d_name[0] == '.' && ~flags & F_ALL_FILES) continue; if (i == db->size) { @@ -90,6 +94,8 @@ int list_dir(dirbuff_t *db, char flags) db->is_file = S_ISDIR(fi.st_mode) && ~flags & F_DIRECTORY; if (db->is_file) { dir = opendir(db->name); + if (dir == NULL) + return print_error(db->name), -1; count = read_directory(db, dir, flags); closedir(dir); } else { From 9b0ebdf161a3d070a4ff514b92203a5f76fdae27 Mon Sep 17 00:00:00 2001 From: Sigmanificient Date: Fri, 19 Apr 2024 23:41:41 +0200 Subject: [PATCH 08/10] Include copyright notice --- src/ls/ls.1 | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/ls/ls.1 b/src/ls/ls.1 index 9611ddf..c7b82a3 100644 --- a/src/ls/ls.1 +++ b/src/ls/ls.1 @@ -34,6 +34,8 @@ sort by time, newest first . .El . +.Sh Copyright +This project is dedicated to the public domain, which means you're free to use it however you like. While mentioning us is optional, we'd greatly appreciate it if you would consider acknowledging our contribution. .Sh AUTHOR Canoutils `ls` was written by \fBSigmanificient\fB. .br From 0fdc477ba6d914233058c80622067f125094bb27 Mon Sep 17 00:00:00 2001 From: Sigmanificient Date: Fri, 19 Apr 2024 23:52:30 +0200 Subject: [PATCH 09/10] Format the code using clang-format --- src/ls/ls.h | 64 +++++++-------- src/ls/ls_list_directories.c | 154 +++++++++++++++-------------------- src/ls/ls_main.c | 99 +++++++++++----------- src/ls/ls_print_info.c | 145 +++++++++++++++------------------ src/ls/ls_recursive_walk.c | 78 +++++++++--------- src/ls/ls_strdup.c | 13 ++- 6 files changed, 251 insertions(+), 302 deletions(-) diff --git a/src/ls/ls.h b/src/ls/ls.h index 3496e20..6696ce1 100644 --- a/src/ls/ls.h +++ b/src/ls/ls.h @@ -1,54 +1,52 @@ #ifndef MY_LS_H - #define MY_LS_H - - #include - #include +#define MY_LS_H - #define ZERO_OR(expr, default) ((!!(expr)) * default) +#include +#include + +#define ZERO_OR(expr, default) ((!!(expr)) * default) #define __USE_XOPEN2K8 #define __USE_MISC - #include - #include +#include +#include - #define MIN_ALLOCATED_ENTRY (1024) +#define MIN_ALLOCATED_ENTRY (1024) - #if !defined(__clang__) || !defined (__GNUC__) - #define __attribute__(x) // omitted - #endif +#if !defined(__clang__) || !defined(__GNUC__) +#define __attribute__(x) // omitted +#endif enum { - F_ALL_FILES = 1 << 0, - F_LONG_FORM = 1 << 1, - F_RECURSIVE = 1 << 2, - F_DIRECTORY = 1 << 3, - F_REV_ORDER = 1 << 4, - F_SORT_TIME = 1 << 5, - F_SHOW_DIRS = 1 << 6, + F_ALL_FILES = 1 << 0, + F_LONG_FORM = 1 << 1, + F_RECURSIVE = 1 << 2, + F_DIRECTORY = 1 << 3, + F_REV_ORDER = 1 << 4, + F_SORT_TIME = 1 << 5, + F_SHOW_DIRS = 1 << 6, }; typedef struct { - struct stat stat; - struct passwd *passwd; - struct group *group; - char name[NAME_MAX + 1]; + struct stat stat; + struct passwd *passwd; + struct group *group; + char name[NAME_MAX + 1]; } entry_t; typedef struct { - char *name; - entry_t *entries; - size_t size; - bool is_file; + char *name; + entry_t *entries; + size_t size; + bool is_file; } dirbuff_t; -inline __attribute__((const)) -int stridx(const char *str, char c) -{ - for (const char *p = str; *p != '\0'; p++) - if (*p == c) - return (int)(p - str); - return -1; +inline __attribute__((const)) int stridx(const char *str, char c) { + for (const char *p = str; *p != '\0'; p++) + if (*p == c) + return (int)(p - str); + return -1; } char *strdup(char const *s); diff --git a/src/ls/ls_list_directories.c b/src/ls/ls_list_directories.c index 225a430..210098c 100644 --- a/src/ls/ls_list_directories.c +++ b/src/ls/ls_list_directories.c @@ -11,107 +11,85 @@ #include "ls.h" -static -void get_file_info(const char *path, entry_t *entry) -{ - if (stat(path, &entry->stat) < 0) - return; - entry->passwd = getpwuid(entry->stat.st_uid); - entry->group = getgrgid(entry->stat.st_gid); +static void get_file_info(const char *path, entry_t *entry) { + if (stat(path, &entry->stat) < 0) + return; + entry->passwd = getpwuid(entry->stat.st_uid); + entry->group = getgrgid(entry->stat.st_gid); } -static __attribute__((nonnull)) -size_t read_directory(dirbuff_t *db, DIR *dir, char flags) -{ - static char path[PATH_MAX]; - size_t i = 0; +static __attribute__((nonnull)) size_t read_directory(dirbuff_t *db, DIR *dir, + char flags) { + static char path[PATH_MAX]; + size_t i = 0; - for ( - struct dirent *dirent = readdir(dir); - dirent != NULL; - dirent = readdir(dir) - ) { - if (dirent->d_name[0] == '.' && ~flags & F_ALL_FILES) - continue; - if (i == db->size) { - db->size <<= 1; - db->entries = realloc( - db->entries, db->size * sizeof(*db->entries)); - } - strcpy(db->entries[i].name, dirent->d_name); - if (flags & (F_LONG_FORM | F_SORT_TIME | F_RECURSIVE)) - get_file_info(path_concat(path, db->name, db->entries[i].name), - &db->entries[i]); - i++; + for (struct dirent *dirent = readdir(dir); dirent != NULL; + dirent = readdir(dir)) { + if (dirent->d_name[0] == '.' && ~flags & F_ALL_FILES) + continue; + if (i == db->size) { + db->size <<= 1; + db->entries = realloc(db->entries, db->size * sizeof(*db->entries)); } - return i; + strcpy(db->entries[i].name, dirent->d_name); + if (flags & (F_LONG_FORM | F_SORT_TIME | F_RECURSIVE)) + get_file_info(path_concat(path, db->name, db->entries[i].name), + &db->entries[i]); + i++; + } + return i; } -static -void print_error(char *dirname) -{ - char const *err = strerror(errno); +static void print_error(char *dirname) { + char const *err = strerror(errno); - switch (errno) { - case ENOENT: - fprintf(stderr, - "ls: cannot access '%s': %s\n", - dirname, err); - return; - case EACCES: - fprintf(stderr, - "ls: cannot open directory '%s': %s\n", - dirname, err); - return; - default: - fprintf(stderr, "ls: %s\n", err); - } + switch (errno) { + case ENOENT: + fprintf(stderr, "ls: cannot access '%s': %s\n", dirname, err); + return; + case EACCES: + fprintf(stderr, "ls: cannot open directory '%s': %s\n", dirname, err); + return; + default: + fprintf(stderr, "ls: %s\n", err); + } } -static -int compare_names(entry_t const *leftp, entry_t const *rightp) -{ - return strcoll(leftp->name, rightp->name); +static int compare_names(entry_t const *leftp, entry_t const *rightp) { + return strcoll(leftp->name, rightp->name); } -static -int compare_times(entry_t const *leftp, entry_t const *rightp) -{ - return (int)( - rightp->stat.st_mtim.tv_sec - - leftp->stat.st_mtim.tv_sec - ); +static int compare_times(entry_t const *leftp, entry_t const *rightp) { + return (int)(rightp->stat.st_mtim.tv_sec - leftp->stat.st_mtim.tv_sec); } -int list_dir(dirbuff_t *db, char flags) -{ - struct stat fi; - size_t count = 1; - DIR *dir; +int list_dir(dirbuff_t *db, char flags) { + struct stat fi; + size_t count = 1; + DIR *dir; - if (stat(db->name, &fi) < 0) - return print_error(db->name), -1; - db->is_file = S_ISDIR(fi.st_mode) && ~flags & F_DIRECTORY; - if (db->is_file) { - dir = opendir(db->name); - if (dir == NULL) - return print_error(db->name), -1; - count = read_directory(db, dir, flags); - closedir(dir); - } else { - strcpy(db->entries[0].name, db->name); - get_file_info(db->name, &db->entries[0]); - } + if (stat(db->name, &fi) < 0) + return print_error(db->name), -1; + db->is_file = S_ISDIR(fi.st_mode) && ~flags & F_DIRECTORY; + if (db->is_file) { + dir = opendir(db->name); + if (dir == NULL) + return print_error(db->name), -1; + count = read_directory(db, dir, flags); + closedir(dir); + } else { + strcpy(db->entries[0].name, db->name); + get_file_info(db->name, &db->entries[0]); + } - qsort(db->entries, count, - sizeof *db->entries, (__compar_fn_t)&compare_names); - if (flags & F_SORT_TIME) - qsort(db->entries, count, - sizeof *db->entries, (__compar_fn_t)&compare_times); - if (flags & (F_SHOW_DIRS | F_RECURSIVE) && !db->is_file) - printf("%s:\n", db->name); - print_entries(db->entries, count, flags); - if (flags & F_RECURSIVE && !db->is_file) - recurse(db, count, flags); - return 0; + qsort(db->entries, count, sizeof *db->entries, (__compar_fn_t)&compare_names); + if (flags & F_SORT_TIME) + qsort(db->entries, count, sizeof *db->entries, + (__compar_fn_t)&compare_times); + if (flags & (F_SHOW_DIRS | F_RECURSIVE) && !db->is_file) + printf("%s:\n", db->name); + print_entries(db->entries, count, flags); + if (flags & F_RECURSIVE && !db->is_file) + recurse(db, count, flags); + return 0; } diff --git a/src/ls/ls_main.c b/src/ls/ls_main.c index 2320a42..e90cf14 100644 --- a/src/ls/ls_main.c +++ b/src/ls/ls_main.c @@ -5,64 +5,57 @@ static const char FLAGLIST[] = "alRdrt"; static char DEFAULT_LOCATION[] = "."; -static -char compose_flaglist(int argc, char **argv) -{ - int flags = 0; - - for (int i = 1; i < argc; i++) { - if (argv[i][0] != '-' || argv[i][1] == '\0') - continue; - for (int j = 1; argv[i][j] != '\0'; j++) - flags |= 1 << (stridx(FLAGLIST, argv[i][j]) + 1); - } - return (char)(flags >> 1); +static char compose_flaglist(int argc, char **argv) { + int flags = 0; + + for (int i = 1; i < argc; i++) { + if (argv[i][0] != '-' || argv[i][1] == '\0') + continue; + for (int j = 1; argv[i][j] != '\0'; j++) + flags |= 1 << (stridx(FLAGLIST, argv[i][j]) + 1); + } + return (char)(flags >> 1); } -static -size_t count_targets(int argc, char **argv) -{ - int count = 0; +static size_t count_targets(int argc, char **argv) { + int count = 0; - for (int i = 1; i < argc; i++) - if (argv[i][0] != '-' || argv[i][1] == '\0') - count++; - return count; + for (int i = 1; i < argc; i++) + if (argv[i][0] != '-' || argv[i][1] == '\0') + count++; + return count; } -static -bool list_dirs(dirbuff_t *db, int argc, char **argv, char flags) -{ - int err = 0; - size_t count = count_targets(argc, argv); - - if (count == 0) { - db->name = DEFAULT_LOCATION; - err |= list_dir(db, flags); - } - for (int i = 1; i < argc; i++) { - if (argv[i][0] == '-' && argv[i][1] != '\0') - continue; - db->name = argv[i]; - if (count > 1) - flags |= F_SHOW_DIRS; - err |= list_dir(db, flags); - } - return err; +static bool list_dirs(dirbuff_t *db, int argc, char **argv, char flags) { + int err = 0; + size_t count = count_targets(argc, argv); + + if (count == 0) { + db->name = DEFAULT_LOCATION; + err |= list_dir(db, flags); + } + for (int i = 1; i < argc; i++) { + if (argv[i][0] == '-' && argv[i][1] != '\0') + continue; + db->name = argv[i]; + if (count > 1) + flags |= F_SHOW_DIRS; + err |= list_dir(db, flags); + } + return err; } -int main(int argc, char **argv) -{ - dirbuff_t db = { .size = MIN_ALLOCATED_ENTRY }; - char flags = compose_flaglist(argc, argv); - int err = 0; - - db.entries = malloc(db.size * sizeof(*db.entries)); - if (db.entries == NULL) - return EXIT_FAILURE; - if (flags & F_DIRECTORY) - flags &= ~F_RECURSIVE; - err |= !list_dirs(&db, argc, argv, flags); - free(db.entries); - return err ? EXIT_SUCCESS : EXIT_FAILURE; +int main(int argc, char **argv) { + dirbuff_t db = {.size = MIN_ALLOCATED_ENTRY}; + char flags = compose_flaglist(argc, argv); + int err = 0; + + db.entries = malloc(db.size * sizeof(*db.entries)); + if (db.entries == NULL) + return EXIT_FAILURE; + if (flags & F_DIRECTORY) + flags &= ~F_RECURSIVE; + err |= !list_dirs(&db, argc, argv, flags); + free(db.entries); + return err ? EXIT_SUCCESS : EXIT_FAILURE; } diff --git a/src/ls/ls_print_info.c b/src/ls/ls_print_info.c index 05e970b..993062d 100644 --- a/src/ls/ls_print_info.c +++ b/src/ls/ls_print_info.c @@ -14,97 +14,82 @@ typedef unsigned char uchar; -static -void get_file_right(char bits[static sizeof("rwxrwxrwx")], entry_t *entry) -{ - char *bitsp = bits; - mode_t mode = entry->stat.st_mode; - static const char *s = "-rwx"; +static void get_file_right(char bits[static sizeof("rwxrwxrwx")], + entry_t *entry) { + char *bitsp = bits; + mode_t mode = entry->stat.st_mode; + static const char *s = "-rwx"; - *bitsp++ = s[(uchar)ZERO_OR(mode & S_IRUSR, 1)]; - *bitsp++ = s[(uchar)ZERO_OR(mode & S_IWUSR, 2)]; - *bitsp++ = s[(uchar)ZERO_OR(mode & S_IXUSR, 3)]; - *bitsp++ = s[(uchar)ZERO_OR(mode & S_IRGRP, 1)]; - *bitsp++ = s[(uchar)ZERO_OR(mode & S_IWGRP, 2)]; - *bitsp++ = s[(uchar)ZERO_OR(mode & S_IXGRP, 3)]; - *bitsp++ = s[(uchar)ZERO_OR(mode & S_IROTH, 1)]; - *bitsp++ = s[(uchar)ZERO_OR(mode & S_IWOTH, 2)]; - *bitsp++ = s[(uchar)ZERO_OR(mode & S_IXOTH, 3)]; - if (mode & S_ISUID) - bits[1] = (mode & S_IXUSR) ? 's' : 'S'; - if (mode & S_ISGID) - bits[3] = (mode & S_IXGRP) ? 's' : 'l'; - if (mode & S_ISVTX) - bits[8] = (mode & S_IXOTH) ? 't' : 'T'; + *bitsp++ = s[(uchar)ZERO_OR(mode & S_IRUSR, 1)]; + *bitsp++ = s[(uchar)ZERO_OR(mode & S_IWUSR, 2)]; + *bitsp++ = s[(uchar)ZERO_OR(mode & S_IXUSR, 3)]; + *bitsp++ = s[(uchar)ZERO_OR(mode & S_IRGRP, 1)]; + *bitsp++ = s[(uchar)ZERO_OR(mode & S_IWGRP, 2)]; + *bitsp++ = s[(uchar)ZERO_OR(mode & S_IXGRP, 3)]; + *bitsp++ = s[(uchar)ZERO_OR(mode & S_IROTH, 1)]; + *bitsp++ = s[(uchar)ZERO_OR(mode & S_IWOTH, 2)]; + *bitsp++ = s[(uchar)ZERO_OR(mode & S_IXOTH, 3)]; + if (mode & S_ISUID) + bits[1] = (mode & S_IXUSR) ? 's' : 'S'; + if (mode & S_ISGID) + bits[3] = (mode & S_IXGRP) ? 's' : 'l'; + if (mode & S_ISVTX) + bits[8] = (mode & S_IXOTH) ? 't' : 'T'; } -static -char get_file_type(entry_t *entry) -{ - const char typ[] = { - [ S_IFBLK ] = 'b', - [ S_IFCHR ] = 'c', - [ S_IFDIR ] = 'd', - [ S_IFIFO ] = 'p', - [ S_IFLNK ] = 'l', - [ S_IFREG ] = '-', - [ S_IFSOCK ] = 's', - [ 0 ] = '?' - }; +static char get_file_type(entry_t *entry) { + const char typ[] = { + [S_IFBLK] = 'b', [S_IFCHR] = 'c', [S_IFDIR] = 'd', [S_IFIFO] = 'p', + [S_IFLNK] = 'l', [S_IFREG] = '-', [S_IFSOCK] = 's', [0] = '?'}; - return typ[(entry->stat.st_mode & S_IFMT)]; + return typ[(entry->stat.st_mode & S_IFMT)]; } -static -char *get_creation_time(entry_t *entry) -{ - static char fmt[sizeof("Jan 01 00:00")]; - char *ct = ctime(&entry->stat.st_mtim.tv_sec); - time_t now = time(NULL); - const int six_month_sec = 6 * 24 * 3600 * 31; +static char *get_creation_time(entry_t *entry) { + static char fmt[sizeof("Jan 01 00:00")]; + char *ct = ctime(&entry->stat.st_mtim.tv_sec); + time_t now = time(NULL); + const int six_month_sec = 6 * 24 * 3600 * 31; - if (strlen(ct) < 24) - return NULL; - if (entry->stat.st_mtim.tv_sec + six_month_sec < now) { - strncpy(fmt, ct + 4, 7); - strncpy(fmt + 7, ct + 19, 5); - } else - strncpy(fmt, ct + 4, 12); - return fmt; + if (strlen(ct) < 24) + return NULL; + if (entry->stat.st_mtim.tv_sec + six_month_sec < now) { + strncpy(fmt, ct + 4, 7); + strncpy(fmt + 7, ct + 19, 5); + } else + strncpy(fmt, ct + 4, 12); + return fmt; } -static -void print_file_infos(entry_t *entry) -{ - struct stat *fi = &entry->stat; - char perms[sizeof("-rwxr-xr-x")] = { [0] = get_file_type(entry), '\0' }; - char const *owner = (entry->passwd == NULL) ? "?" : entry->passwd->pw_name; - char const *grp = (entry->group == NULL) ? "?" : entry->group->gr_name; - char *time = get_creation_time(entry); +static void print_file_infos(entry_t *entry) { + struct stat *fi = &entry->stat; + char perms[sizeof("-rwxr-xr-x")] = {[0] = get_file_type(entry), '\0'}; + char const *owner = (entry->passwd == NULL) ? "?" : entry->passwd->pw_name; + char const *grp = (entry->group == NULL) ? "?" : entry->group->gr_name; + char *time = get_creation_time(entry); - get_file_right(perms + 1, entry); - printf("%.10s %ld %s %s ", perms, fi->st_nlink, owner, grp); - if (stridx("bc", perms[0]) != -1) - printf("%d, %d", major(fi->st_rdev), minor(fi->st_rdev)); - else - printf("%ld", fi->st_size); - printf(" %.12s ", time); + get_file_right(perms + 1, entry); + printf("%.10s %ld %s %s ", perms, fi->st_nlink, owner, grp); + if (stridx("bc", perms[0]) != -1) + printf("%d, %d", major(fi->st_rdev), minor(fi->st_rdev)); + else + printf("%ld", fi->st_size); + printf(" %.12s ", time); } -void print_entries(entry_t *entry, size_t count, char flags) -{ - int d; +void print_entries(entry_t *entry, size_t count, char flags) { + int d; - if (flags & F_REV_ORDER) { - d = -1; - entry += (count - 1); - } else - d = 1; - for (size_t i = 0; i < count; i++) { - if (flags & F_LONG_FORM) - print_file_infos(entry); - printf("%s", entry->name); - printf(((i + 1) == count || flags & F_LONG_FORM) ? "\n" : " "); - entry += d; - } + if (flags & F_REV_ORDER) { + d = -1; + entry += (count - 1); + } else + d = 1; + for (size_t i = 0; i < count; i++) { + if (flags & F_LONG_FORM) + print_file_infos(entry); + printf("%s", entry->name); + printf(((i + 1) == count || flags & F_LONG_FORM) ? "\n" : " "); + entry += d; + } } diff --git a/src/ls/ls_recursive_walk.c b/src/ls/ls_recursive_walk.c index 916a8c3..78c9164 100644 --- a/src/ls/ls_recursive_walk.c +++ b/src/ls/ls_recursive_walk.c @@ -3,53 +3,49 @@ #include "ls.h" -char *path_concat(char *dest, char *basepath, char *suffix) -{ - unsigned long written = 0; +char *path_concat(char *dest, char *basepath, char *suffix) { + unsigned long written = 0; - strcpy(dest, basepath); - written = strlen(basepath); - if (dest[written - 1] != '/') { - dest[written] = '/'; - written++; - } - strcpy(dest + written, suffix); - written += strlen(suffix); - dest[written] = '\0'; - return dest; + strcpy(dest, basepath); + written = strlen(basepath); + if (dest[written - 1] != '/') { + dest[written] = '/'; + written++; + } + strcpy(dest + written, suffix); + written += strlen(suffix); + dest[written] = '\0'; + return dest; } -static __attribute__((nonnull)) -size_t find_directories(char **dirs, dirbuff_t *db, size_t count) -{ - size_t found = 0; +static __attribute__((nonnull)) size_t +find_directories(char **dirs, dirbuff_t *db, size_t count) { + size_t found = 0; - for (size_t i = 0; i < count; i++) { - if (!strcmp(db->entries[i].name, ".") - || !strcmp(db->entries[i].name, "..")) - continue; - if (S_ISDIR(db->entries[i].stat.st_mode)) { - dirs[found] = strdup(db->entries[i].name); - found++; - } + for (size_t i = 0; i < count; i++) { + if (!strcmp(db->entries[i].name, ".") || !strcmp(db->entries[i].name, "..")) + continue; + if (S_ISDIR(db->entries[i].stat.st_mode)) { + dirs[found] = strdup(db->entries[i].name); + found++; } - return found; + } + return found; } -size_t recurse(dirbuff_t *db, size_t count, char flags) -{ - static char path[PATH_MAX]; - size_t dirsize = strlen(db->name); - char **dirs = malloc(count * sizeof(char *)); - size_t j = find_directories(dirs, db, count); +size_t recurse(dirbuff_t *db, size_t count, char flags) { + static char path[PATH_MAX]; + size_t dirsize = strlen(db->name); + char **dirs = malloc(count * sizeof(char *)); + size_t j = find_directories(dirs, db, count); - for (size_t i = 0; i < j; i++) { - db->name = path_concat(path, db->name, dirs[i]); - list_dir(db, flags); - db->name[dirsize] = '\0'; - } - for (size_t i = 0; i < j; i++) - free(dirs[i]); - free(dirs); - return 0; + for (size_t i = 0; i < j; i++) { + db->name = path_concat(path, db->name, dirs[i]); + list_dir(db, flags); + db->name[dirsize] = '\0'; + } + for (size_t i = 0; i < j; i++) + free(dirs[i]); + free(dirs); + return 0; } diff --git a/src/ls/ls_strdup.c b/src/ls/ls_strdup.c index 12d056b..c67be60 100644 --- a/src/ls/ls_strdup.c +++ b/src/ls/ls_strdup.c @@ -3,12 +3,11 @@ #include "ls.h" -char *strdup(char const *s) -{ - size_t len = strlen(s); - char *dupped = malloc(len + 1); +char *strdup(char const *s) { + size_t len = strlen(s); + char *dupped = malloc(len + 1); - strcpy(dupped, s); - dupped[len] = '\0'; - return dupped; + strcpy(dupped, s); + dupped[len] = '\0'; + return dupped; } From 24c8b591e246cbcccd90f95ef069d4c3ebe13744 Mon Sep 17 00:00:00 2001 From: Sigmanificient Date: Sat, 20 Apr 2024 00:01:34 +0200 Subject: [PATCH 10/10] Add version info --- src/ls/ls_main.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/src/ls/ls_main.c b/src/ls/ls_main.c index e90cf14..50b8ceb 100644 --- a/src/ls/ls_main.c +++ b/src/ls/ls_main.c @@ -1,7 +1,18 @@ +#include #include +#include #include "ls.h" +#define NAME "ls (canoutils)" +#define VERSION "1.0.0" +#define AUTHOR "Yohann Boniface (Sigmanificient)" + +#define print_version() \ + do { \ + printf("%s\nversion: %s\nby: %s\n", NAME, VERSION, AUTHOR); \ + } while (0) + static const char FLAGLIST[] = "alRdrt"; static char DEFAULT_LOCATION[] = "."; @@ -47,9 +58,13 @@ static bool list_dirs(dirbuff_t *db, int argc, char **argv, char flags) { int main(int argc, char **argv) { dirbuff_t db = {.size = MIN_ALLOCATED_ENTRY}; - char flags = compose_flaglist(argc, argv); + char flags; int err = 0; + for (int i = 0; argv[i] != NULL; i++) + if (!strcmp(argv[i], "--version")) + return printf(VERSION), EXIT_SUCCESS; + flags = compose_flaglist(argc, argv); db.entries = malloc(db.size * sizeof(*db.entries)); if (db.entries == NULL) return EXIT_FAILURE;