Skip to content

Commit

Permalink
Merge branch 'proh14:main' into cat
Browse files Browse the repository at this point in the history
  • Loading branch information
SzAkos04 authored Apr 19, 2024
2 parents cfe098b + fe851b9 commit 6e95c6f
Show file tree
Hide file tree
Showing 12 changed files with 491 additions and 10 deletions.
29 changes: 29 additions & 0 deletions .github/workflows/fmt-check.yml
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
1 change: 1 addition & 0 deletions flake.nix
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
bear
python3Packages.compiledb
gcovr
clang-tools
];
};

Expand Down
5 changes: 4 additions & 1 deletion src/ls/Makefile
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
42 changes: 41 additions & 1 deletion src/ls/ls.1
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
6 changes: 0 additions & 6 deletions src/ls/ls.c

This file was deleted.

60 changes: 60 additions & 0 deletions src/ls/ls.h
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
95 changes: 95 additions & 0 deletions src/ls/ls_list_directories.c
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;
}
76 changes: 76 additions & 0 deletions src/ls/ls_main.c
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;
}
Loading

0 comments on commit 6e95c6f

Please sign in to comment.