diff options
| -rw-r--r-- | ls.c | 144 |
1 files changed, 102 insertions, 42 deletions
@@ -1,7 +1,7 @@ /* * UNG's Not GNU * - * Copyright (c) 2011-2019, Jakob Kaivo <jkk@ung.org> + * Copyright (c) 2011-2022, Jakob Kaivo <jkk@ung.org> * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -23,6 +23,7 @@ */ #define _XOPEN_SOURCE 700 +#include <locale.h> #include <stdio.h> #include <stdint.h> #include <sys/stat.h> @@ -89,6 +90,8 @@ static int columns = 80; struct ls_entry { char name[PATH_MAX]; + struct stat st; + uintmax_t size; ino_t inode; time_t time; @@ -280,7 +283,7 @@ static int ls_compare(struct ls_entry *e1, struct ls_entry *e2) } else if (sort == DIRECTORY) { return (reverse ? -1 : 1); } - return (reverse ? -1 : 1) * (strcmp(e1->name, e2->name)); + return (reverse ? -1 : 1) * (strcoll(e1->name, e2->name)); } static int ls_add(const char *path, int do_stat) @@ -467,113 +470,162 @@ static void ls_print(struct ls_entry *c) } } -int main(int argc, char **argv) +static int ls_compare_operands(const void *op_a, const void *op_b) { + const char *a = *(char**)op_a; + const char *b = *(char**)op_b; + struct stat sta, stb; + if (stat(a, &sta) == 0 && stat(b, &stb) == 0) { + if (S_ISDIR(sta.st_mode) && !S_ISDIR(stb.st_mode)) { + return 1; + } + if (S_ISDIR(stb.st_mode) && !S_ISDIR(sta.st_mode)) { + return -1; + } + } + + return strcoll(a, b); +} + +int main(int argc, char *argv[]) +{ + setlocale(LC_ALL, ""); + struct stat st; - char *files[ARG_MAX]; + char *files[argc]; int c; int i = 0, f = 0; int lastfollow = 0; char *cols = getenv("COLUMNS"); - if (cols != NULL) + if (cols != NULL) { columns = atoi(cols); + } + + if (!isatty(STDOUT_FILENO)) { + display = SINGLE; + } while ((c = getopt(argc, argv, ":ACFRSacdgfiklmnoprstux1HL")) != -1) { switch (c) { - case 'A': + case 'A': /** all but . and .. **/ all = ALMOST; break; - case 'C': + + case 'C': /** sort in columns **/ display = COLUMNS; break; - case 'F': + + case 'F': /** append file type characters **/ format |= CHARACTER; break; - case 'H': - if (links != NONE) - return 1; + + case 'H': /** follow symbolic links on command line **/ links = FOLLOW; break; - case 'L': - if (links != NONE) - return 1; + + case 'L': /** follow all symbolic links **/ links = LLONG; break; - case 'R': + + case 'R': /** run recursively **/ recurse = 1; break; - case 'S': + + case 'S': /** sort by size **/ sort = SIZE; break; - case 'a': + + case 'a': /** output all files **/ all = ALL; break; - case 'c': + + case 'c': /** sort by change time **/ sort = CTIME; break; - case 'd': + + case 'd': /** do not enter directories **/ listdirs = 1; break; - case 'f': + + case 'f': /** do not sort **/ sort = DIRECTORY; all = ALL; display = ROWS; format ^= BLOCKS; recurse = 0; break; - case 'g': + + case 'g': /** like -l, but without owner **/ display = LONG; noowner = 1; break; - case 'i': + + case 'i': /** include file serial numbers **/ format |= INODES; break; - case 'k': + + case 'k': /** use a blocksize of 1024 **/ blocksize = 1024; break; - case 'l': + + case 'l': /** output full details **/ display = LONG; break; - case 'm': + + case 'm': /** stream output separated by commas **/ display = COMMA; break; - case 'n': + + case 'n': /** like -l, but with numeric UID and GID **/ display = LONG; numeric = 1; break; - case 'o': + + case 'o': /** like -l, but without group **/ display = LONG; nogroup = 1; break; - case 'p': + + case 'p': /** append / after directory names **/ format |= DIRS; break; - case 'q': + + case 'q': /** replace non-printable characters with ? **/ format |= QUOTE; // FIXME break; - case 'r': + + case 'r': /** reverse sort order **/ reverse = 1; break; - case 's': + + case 's': /** outpu total number of blocks **/ format |= BLOCKS; // FIXME break; - case 't': + + case 't': /** sort by modified time **/ sort = MTIME; break; - case 'u': + + case 'u': /** sort by access time **/ sort = ATIME; break; - case 'x': + + case 'x': /** sort across rows first **/ display = ROWS; break; - case '1': + + case '1': /** output one file per line **/ display = SINGLE; break; + default: return 1; } } + /* sort operands */ + qsort(argv + optind, argc - optind, sizeof(*argv), ls_compare_operands); + if (optind >= argc) { strcpy(dirlist[0].path, "."); strcpy(dirlist[0].display, "."); @@ -594,35 +646,43 @@ int main(int argc, char **argv) optind++; } - if (links == FOLLOW) + if (links == FOLLOW) { lastfollow = totaldirs; + } - for (i = 0; i < f; i++) + for (i = 0; i < f; i++) { ls_add(files[i], 0); + } ls_print(root); ls_reset(); - if (f > 0 && totaldirs > 0) + if (f > 0 && totaldirs > 0) { putchar('\n'); + } for (i = 0; i < totaldirs; i++) { int total = 0; - if (i >= lastfollow && links == FOLLOW) + if (i >= lastfollow && links == FOLLOW) { links = NONE; + } total = ls_dir(dirlist[i].path); - if (f > 0 || totaldirs > 1) + if (f > 0 || totaldirs > 1) { printf("%s:\n", dirlist[i].display); - if (display == LONG || format & BLOCKS) + } + + if (display == LONG || format & BLOCKS) { printf("total %u\n", total); + } ls_print(root); - if (totaldirs > i + 1) + if (totaldirs > i + 1) { putchar('\n'); + } ls_reset(); } |
