-
Notifications
You must be signed in to change notification settings - Fork 8
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
12 changed files
with
491 additions
and
10 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
on: | ||
workflow_dispatch: | ||
push: | ||
paths: | ||
- "**.c" | ||
- "**.h" | ||
- ".github/workflows/fmt-check.yml" | ||
|
||
jobs: | ||
check: | ||
runs-on: ubuntu-latest | ||
steps: | ||
- uses: actions/checkout@v4 | ||
- uses: cachix/install-nix-action@v26 | ||
with: | ||
nix_path: nixpkgs=channel:nixos-unstable | ||
|
||
- run: | | ||
nix build nixpkgs#clang-tools | ||
find . -type f -name "*.c" -or -name "*.h" \ | ||
| xargs -i ./result/bin/clang-format -i {} | ||
out=$(git status \ | ||
| grep "modified" \ | ||
| cut -d ":" -f 2 \ | ||
| sort \ | ||
| xargs \ | ||
| tee /dev/stderr \ | ||
| wc -c) | ||
[ $out -ge 1 ] && exit 1 || exit 0 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -25,6 +25,7 @@ | |
bear | ||
python3Packages.compiledb | ||
gcovr | ||
clang-tools | ||
]; | ||
}; | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,8 @@ | ||
OUT := ls | ||
|
||
SRC := ls.c | ||
SRC := ls_main.c | ||
SRC += ls_list_directories.c | ||
SRC += ls_print_info.c | ||
SRC += ls_recursive_walk.c | ||
|
||
include ../shared.mk |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,41 @@ | ||
\" TODO | ||
.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 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 |
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
#ifndef MY_LS_H | ||
#define MY_LS_H | ||
|
||
#include <stdbool.h> | ||
#include <stddef.h> | ||
|
||
#define ZERO_OR(expr, default) ((!!(expr)) * default) | ||
|
||
#define __USE_XOPEN2K8 | ||
#define __USE_MISC | ||
|
||
#include <linux/limits.h> | ||
#include <sys/stat.h> | ||
|
||
#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, | ||
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; | ||
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; | ||
} | ||
|
||
char *strdup(char const *s); | ||
|
||
int list_dir(dirbuff_t *db, char flags); | ||
size_t recurse(dirbuff_t *db, size_t count, char flags); | ||
|
||
void print_entries(entry_t *entry, size_t count, char flags); | ||
char *path_concat(char *dest, char *basepath, char *suffix); | ||
|
||
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
#include <dirent.h> | ||
#include <errno.h> | ||
#include <grp.h> | ||
#include <pwd.h> | ||
#include <stddef.h> | ||
#include <stdio.h> | ||
#include <stdlib.h> | ||
#include <string.h> | ||
#include <sys/types.h> | ||
#include <unistd.h> | ||
|
||
#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 __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++; | ||
} | ||
return i; | ||
} | ||
|
||
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); | ||
} | ||
} | ||
|
||
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); | ||
} | ||
|
||
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]); | ||
} | ||
|
||
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; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
#include <stdio.h> | ||
#include <stdlib.h> | ||
#include <string.h> | ||
|
||
#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[] = "."; | ||
|
||
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; | ||
|
||
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; | ||
} | ||
|
||
int main(int argc, char **argv) { | ||
dirbuff_t db = {.size = MIN_ALLOCATED_ENTRY}; | ||
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; | ||
if (flags & F_DIRECTORY) | ||
flags &= ~F_RECURSIVE; | ||
err |= !list_dirs(&db, argc, argv, flags); | ||
free(db.entries); | ||
return err ? EXIT_SUCCESS : EXIT_FAILURE; | ||
} |
Oops, something went wrong.