[syslinux:pathbased] dir.c32: sort, columize and page the output

syslinux-bot for H. Peter Anvin hpa at zytor.com
Sat Mar 6 14:54:14 PST 2010


Commit-ID:  c6dad6100dfe90859b026a5218602224eaf9c585
Gitweb:     http://syslinux.zytor.com/commit/c6dad6100dfe90859b026a5218602224eaf9c585
Author:     H. Peter Anvin <hpa at zytor.com>
AuthorDate: Sat, 6 Mar 2010 14:52:35 -0800
Committer:  H. Peter Anvin <hpa at zytor.com>
CommitDate: Sat, 6 Mar 2010 14:52:35 -0800

dir.c32: sort, columize and page the output

Make the output of dir.c32 actually usable for an average user.
Present the directory contents sorted in columns, and pause for every
screenful.

Signed-off-by: H. Peter Anvin <hpa at zytor.com>


---
 com32/modules/dir.c |  162 ++++++++++++++++++++++++++++++++++++++++++++++-----
 1 files changed, 146 insertions(+), 16 deletions(-)

diff --git a/com32/modules/dir.c b/com32/modules/dir.c
index 913c2ca..cb83f97 100644
--- a/com32/modules/dir.c
+++ b/com32/modules/dir.c
@@ -1,35 +1,165 @@
 /*
- * A dir test module
+ * Display directory contents
  */
+#include <stdlib.h>
 #include <stdio.h>
 #include <console.h>
 #include <string.h>
 #include <com32.h>
 #include <dirent.h>
+#include <minmax.h>
+#include <unistd.h>
+#include <getkey.h>
 
-int main(int argc, char *argv[])
+static int rows, cols;		/* Screen parameters */
+
+#define DIR_CHUNK	1024
+
+static const char *type_str(int type)
+{
+    switch (type) {
+    case DT_FIFO:
+	return "[fif]";
+    case DT_CHR:
+	return "[chr]";
+    case DT_DIR:
+	return "[dir]";
+    case DT_BLK:
+	return "[blk]";
+    case DT_UNKNOWN:
+    case DT_REG:
+	return "";
+    case DT_LNK:
+	return "[lnk]";
+    case DT_SOCK:
+	return "[sck]";
+    case DT_WHT:
+	return "[wht]";
+    default:
+	return "[???]";
+    }
+}
+
+static void free_dirents(struct dirent **dex, size_t n_de)
+{
+    size_t i;
+
+    for (i = 0; i < n_de; i++)
+	free(dex[i]);
+
+    free(dex);
+}
+
+static int compare_dirent(const void *p_de1, const void *p_de2)
+{
+    const struct dirent *de1 = *(const struct dirent **)p_de1;
+    const struct dirent *de2 = *(const struct dirent **)p_de2;
+    int ndir1, ndir2;
+
+    ndir1 = de1->d_type != DT_DIR;
+    ndir2 = de2->d_type != DT_DIR;
+
+    if (ndir1 != ndir2)
+	return ndir1 - ndir2;
+
+    return strcmp(de1->d_name, de2->d_name);
+}
+
+static int display_directory(const char *dirname)
 {
     DIR *dir;
     struct dirent *de;
-    
-    openconsole(&dev_null_r, &dev_stdcon_w);
+    struct dirent **dex = NULL;
+    size_t n_dex = 0, n_de = 0;
+    size_t i, j;
+    unsigned int nrows, ncols;
+    int maxlen = 0;
+    int pos, tpos, colwidth, pagerow;
+
+    dir = opendir(dirname);
+    if (!dir) {
+	printf("Unable to read directory: %s\n", dirname);
+	return -1;
+    }
+
+    while ((de = readdir(dir)) != NULL) {
+	struct dirent *nde;
+
+	if (n_de >= n_dex) {
+	    struct dirent **ndex;
+
+	    ndex = realloc(dex, (n_dex + DIR_CHUNK) * sizeof *dex);
+	    if (!ndex)
+		goto nomem;
+
+	    dex = ndex;
+	    n_dex += DIR_CHUNK;
+	}
+
+	nde = malloc(de->d_reclen);
+	if (!nde)
+	    goto nomem;
+
+	memcpy(nde, de, de->d_reclen);
+	dex[n_de++] = nde;
+
+	maxlen = max(maxlen, de->d_reclen);
+    }
+
+    closedir(dir);
+
+    qsort(dex, n_de, sizeof *dex, compare_dirent);
+
+    maxlen -= offsetof(struct dirent, d_name) + 1;
+    ncols = (cols + 2)/(maxlen + 8);
+    ncols = min(ncols, n_de);
+    ncols = max(ncols, 1U);
+    colwidth = (cols + 2)/ncols;
+    nrows = (n_de + ncols - 1) / ncols;
+
+    pagerow = 1;		/* Need one row for the cursor */
+    for (i = 0; i < nrows; i++) {
+	pos = tpos = 0;
+	for (j = i; j < n_de; j += nrows) {
+	    pos += printf("%*s%-5s %s",
+			  (tpos - pos), "",
+			  type_str(dex[j]->d_type),
+			  dex[j]->d_name);
+	    tpos += colwidth;
+	}
+	printf("\n");
+	pagerow++;
+	if (pagerow >= rows) {
+	    get_key(stdin, 0);
+	    pagerow = 1;
+	}
+    }
+
+    free_dirents(dex, n_de);
+    return 0;
+
+nomem:
+    closedir(dir);
+    printf("Out of memory error!\n");
+    free_dirents(dex, n_de);
+    return -1;
+}
+
+int main(int argc, char *argv[])
+{
+    openconsole(&dev_rawcon_r, &dev_stdcon_w);
     
     if (argc != 2) {
-	printf("Usage: dir direcotry\n");
+	printf("Usage: dir directory\n");
 	return 0;
     }
     
-    dir = opendir(argv[1]);
-    if (dir == NULL) {
-	printf("Unable to read dir: %s\n", argv[1]);
-	return 0;
+    if (getscreensize(1, &rows, &cols)) {
+	/* Unknown screen size? */
+	rows = 24;
+	cols = 80;
     }
-    
-    while ((de = readdir(dir)) != NULL)
-	printf("%s\n", de->d_name);
-    
-    closedir(dir);
-    
-    return 0;
+
+    return display_directory(argv[1]);
 }
   



More information about the Syslinux-commits mailing list