summaryrefslogtreecommitdiff
path: root/src/ls.c
diff options
context:
space:
mode:
authorRich Felker <dalias@aerifal.cx>2012-04-12 01:38:35 -0400
committerRich Felker <dalias@aerifal.cx>2012-04-12 01:38:35 -0400
commit02d288d89683e99fd18fe9f54d4e731a6c474a4f (patch)
tree0f9f205ea977d95aad085663fbc36d6002454bc7 /src/ls.c
downloadnoxcuse-02d288d89683e99fd18fe9f54d4e731a6c474a4f.tar.gz
initial check-in
Diffstat (limited to 'src/ls.c')
-rw-r--r--src/ls.c80
1 files changed, 80 insertions, 0 deletions
diff --git a/src/ls.c b/src/ls.c
new file mode 100644
index 0000000..defee1e
--- /dev/null
+++ b/src/ls.c
@@ -0,0 +1,80 @@
+/*
+ * ls.c
+ * Implementation of SUSv3 XCU ls utility
+ * Copyright © 2007 Rich Felker
+ * Licensed under the terms of the GNU General Public License, v2 or later
+ */
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <stdio.h>
+#include <wchar.h>
+#include <wctype.h>
+#include <unistd.h>
+#include <limits.h>
+#include <locale.h>
+#include <errno.h>
+
+static size_t mbswidth(const char *s)
+{
+ size_t l, w=0;
+ int v;
+ wchar_t wc;
+ mbstate_t mbs = { 0 };
+ for (w=0; *s; s+=l, w+=v)
+ if ((l=mbrtowc(&wc, s, MB_LEN_MAX, &mbs))+2<2
+ || (v=wcwidth(wc)) < 0)
+ return -1;
+ return w;
+}
+
+static void my_perror(char *prog, char *msg)
+{
+ char *err = strerror(errno);
+ write(2, prog, strlen(prog));
+ write(2, ": ", 2);
+ write(2, msg, strlen(msg));
+ write(2, ": ", 2);
+ write(2, err, strlen(err));
+ write(2, "\n", 1);
+}
+
+static int cmp(const void *a, const void *b)
+{
+ return strcoll(*(const char **)a, *(const char **)b);
+}
+
+int main(int argc, char *argv[])
+{
+ struct stat st;
+ int (*xstat)(const char *, struct stat *) = stat;
+
+ if (!setlocale(LC_ALL, ""))
+ my_perror(argv[0], "setlocale");
+
+ while ((b=getopt(argc,argv,"CFHLRacdfgilmnoprstux1"))!=EOF) switch(b) {
+ default:
+ return 1;
+ }
+
+ if (optind == argc) {
+ }
+
+ for (i=optind; i<argc; ) {
+ if (xstat(argv[i], &st)) {
+ my_perror(argv[0], argv[i]);
+ memmove(&argv[i], &argv[i+1], argc-i-1);
+ argc--;
+ } else if (S_ISDIR(st.st_mode) && !opt_d) {
+ char *tmp = argv[i];
+ argv[i] = argv[--firstdir];
+ argv[fisrtdir] = tmp;
+ if (i == firstdir) break;
+ } else i++;
+ }
+ qsort(argv+optind, firstdir-optind, sizeof(char *), cmp);
+ qsort(argv+firstdir, argc-firstdir, sizeof(char *), cmp);
+}
+
+