BarryServer : Git

All the code for all my projects
// BarryServer : Git / OrionUserland / blob / 19aefaad8af9de8719ba1e5b5340e0a1b9c68853 / ls / main.c

// Related

OrionUserland

Barry Importing existing Orion Userland 19aefaa (2 years, 4 months ago)
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <dirent.h>
#include <termios.h>
#include <pwd.h>
#include <grp.h>

char *progname;
#include "arg.h"

Winsize termsz;
int allFlag = 0;
int longFlag = 0;

/* Structure for a result */
typedef struct Result Result;
struct Result {
	Result *next, *prev;
	ino_t ino;
	enum DirType type;
	size_t namelen;
	char name[255];
	Stat stat;
};

/* Compare results by name */
static int
compare_name(Result *a, Result *b)
{
	return (strcmp(a->name, b->name) < 0);
}

/* Compare results by type */
static int
compare_type(Result *a, Result *b)
{
	return (a->type == DT_DIR && b->type != DT_DIR);
}

/* Sort a list of results */
static Result *
sort_results(Result *head, int (*compare)(Result *, Result *))
{
	Result *curr, *shead = NULL, *slast, *scurr;
	int i, len = 0;
	for (curr = head; curr; curr = curr->next)
		len++;

	/* Sort */
	for (i = 0; i < len; i++) {
		scurr = head;
		for (curr = head->next; curr; curr = curr->next) {
			if (compare(curr, scurr))
				scurr = curr;
		}

		/* Unlink from old list */
		if (scurr == head)
			head = scurr->next;
		if (scurr->next)
			scurr->next->prev = scurr->prev;
		if (scurr->prev)
			scurr->prev->next = scurr->next;
		scurr->prev = scurr->next = NULL;

		/* Add to sorted list */
		if (!shead) {
			shead = scurr;
		} else {
			scurr->prev = slast;
			slast->next = scurr;
		}
		slast = scurr;
	}

	return shead;
}

/* Print normal results */
static void
print_normal(Result *head)
{
	Result *curr, *next, *prev;
	size_t printed = 0;

	for (curr = head; curr; curr = next) {
		prev = curr->prev;
		next = curr->next;

		int executable = 0;
		if ((curr->stat.mode & S_IXUSR)
		 || (curr->stat.mode & S_IXGRP)
		 || (curr->stat.mode & S_IXOTH))
			executable = 1;

		if (curr->type == DT_DIR)
			printf("\033[1;34m%s\033[0m  ", curr->name);
		else if (curr->type == DT_CHR || curr->type == DT_BLK)
			printf("\033[1;33m%s\033[0m  ", curr->name);
		else if (curr->type == DT_LNK)
			printf("\033[1;36m%s\033[0m  ", curr->name);
		else if (curr->type == DT_REG && executable)
			printf("\033[1;32m%s\033[0m  ", curr->name);
		else
			printf("%s  ", curr->name);
		printed++;

		/* Remove from list */
		if (prev)
			prev->next = next;
		if (next)
			next->prev = prev;
		if (curr == head)
			head = next;
		free(curr);
	}
	if (printed)
		putchar('\n');
}

/* Print long results */
static void
print_long(Result *head)
{
	Result *curr, *next, *prev;
	size_t printed = 0;

	/* Find max column widths */
	size_t total = 0;
	int linkWidth = 0, unameWidth = 0, groupWidth = 0, sizeWidth = 0;
	for (curr = head; curr; curr = curr->next) {
		int linkTmp = curr->stat.nlink, linkWidthTmp = 1;
		while (linkTmp /= 10)
			linkWidthTmp++;
		if (linkWidthTmp > linkWidth)
			linkWidth = linkWidthTmp;

		Passwd *pwd = getpwuid(curr->stat.uid);
		if (strlen(pwd->username) > unameWidth)
			unameWidth = strlen(pwd->username);
		Group *grp = getgrgid(curr->stat.gid);
		if (strlen(grp->name) > groupWidth)
			groupWidth = strlen(grp->name);

		int sizeTmp = curr->stat.size, sizeWidthTmp = 1;
		while (sizeTmp /= 10)
			sizeWidthTmp++;
		if (sizeWidthTmp > sizeWidth)
			sizeWidth = sizeWidthTmp;

		total += (curr->stat.size + (1024 - 1)) / 1024;
	}

	/* Print out */
	printf("total %d\n", total);
	for (curr = head; curr; curr = next) {
		prev = curr->prev;
		next = curr->next;

		char perm[] = "----------";
		char type[] = "?-dcbfsl";
		char uname[33], group[33];
		int executable = 0;
		perm[0] = type[curr->type];
		perm[1] = (curr->stat.mode & S_IRUSR) ? 'r' : '-';
		perm[2] = (curr->stat.mode & S_IWUSR) ? 'w' : '-';
		perm[3] = (curr->stat.mode & S_IXUSR) ? 'x' : '-';
		perm[4] = (curr->stat.mode & S_IRGRP) ? 'r' : '-';
		perm[5] = (curr->stat.mode & S_IWGRP) ? 'w' : '-';
		perm[6] = (curr->stat.mode & S_IXGRP) ? 'x' : '-';
		perm[7] = (curr->stat.mode & S_IROTH) ? 'r' : '-';
		perm[8] = (curr->stat.mode & S_IWOTH) ? 'w' : '-';
		perm[9] = (curr->stat.mode & S_IXOTH) ? 'x' : '-';
		Passwd *pwd = getpwuid(curr->stat.uid);
		Group *grp = getgrgid(curr->stat.gid);
		if ((curr->stat.mode & S_IXUSR)
		 || (curr->stat.mode & S_IXGRP)
		 || (curr->stat.mode & S_IXOTH))
			executable = 1;

		printf("%s %*d %*s %*s %*d ", perm,
		       linkWidth, curr->stat.nlink,
		       -unameWidth, pwd->username,
		       -groupWidth, grp->name,
		       sizeWidth, curr->stat.size);

		if (curr->type == DT_DIR)
			printf("\033[1;34m%s\033[0m\n", curr->name);
		else if (curr->type == DT_CHR || curr->type == DT_BLK)
			printf("\033[1;33m%s\033[0m\n", curr->name);
		else if (curr->type == DT_LNK)
			printf("\033[1;36m%s\033[0m\n", curr->name);
		else if (curr->type == DT_REG && executable)
			printf("\033[1;32m%s\033[0m\n", curr->name);
		else
			printf("%s\n", curr->name);
		printed++;

		/* Remove from list */
		if (prev)
			prev->next = next;
		if (next)
			next->prev = prev;
		if (curr == head)
			head = next;
		free(curr);
	}
}

/* List files in a directory */
static void
ls(char *name)
{
	int fd, sz, i;
	char *buf, cwd[1024];
	struct stat statbuf;
	struct dirent *de;

	Result *head = NULL, *prev = NULL, *next, *curr;
	size_t len = 0, longest = 0;

	fd = open(name, O_RDONLY);
	if (fd < 0) {
		printf("%s: %s: ", progname, name);
		perror(NULL);
		return;
	}

	stat(name, &statbuf);
	if (!S_ISDIR(statbuf.mode)) {
		close(fd);
		return;
	}

	getcwd(cwd, 1024);
	chdir(name);

	/* Get Directory Entries */
	buf = malloc(512);
	sz = getdents(fd, buf, 512);
	for (de = (void *) buf;
	     de < (struct dirent *) (buf + sz);
	     de = (void *) de + de->namelen + sizeof(struct dirent)) {
		if (de->name[0] == '.' && !allFlag)
			continue;
		curr = malloc(sizeof(Result));
		curr->next = NULL;
		curr->prev = prev;
		curr->ino = de->ino;
		curr->type = de->type;
		curr->namelen = de->namelen;
		memcpy(curr->name, de->name, de->namelen);
		curr->name[de->namelen] = '\0';
		stat(curr->name, &curr->stat);
		if (prev)
			prev->next = curr;
		else
			head = curr;
		prev = curr;
		len++;

		if (longest < curr->namelen)
			longest = curr->namelen;
	}
	free(buf);
	close(fd);

	head = sort_results(head, compare_name);
	head = sort_results(head, compare_type);

	if (longFlag)
		print_long(head);
	else
		print_normal(head);

	chdir(cwd);
}

/* Main function */
int
main(int argc, char *argv[])
{
	int i;
	ioctl(STDOUT_FILENO, TCGWINSZ, &termsz);

	ARGBEGIN {
	case 'a':
		allFlag = 1;
		break;
	case 'l':
		longFlag = 1;
		break;
	default:
		printf("Usage:\n");
	} ARGEND;

	if (argc == 0) {
		ls(".");
		return 0;
	}

	if (argc == 1) {
		ls(argv[0]);
		return 0;
	}

	for (i = 0; i < argc; i++) {
		printf("%s:\n", argv[i]);
		ls(argv[i]);
		if (i < argc-1)
			printf("\n");
	}

	return 0;
}