diff options
Diffstat (limited to 'com32/modules/dir.c')
-rw-r--r-- | com32/modules/dir.c | 175 |
1 files changed, 175 insertions, 0 deletions
diff --git a/com32/modules/dir.c b/com32/modules/dir.c new file mode 100644 index 00000000..01a99ed5 --- /dev/null +++ b/com32/modules/dir.c @@ -0,0 +1,175 @@ +/* + * 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> + +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; + struct dirent **dex = NULL; + size_t n_dex = 0, n_de = 0; + size_t i, j, k; + size_t nrows, ncols, perpage; + size_t endpage; + int maxlen = 0; + int pos, tpos, colwidth; + + 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; + perpage = ncols * (rows - 1); + + for (i = 0; i < n_de; i += perpage) { + /* Rows on this page */ + endpage = min(i+perpage, n_de); + nrows = ((endpage-i) + ncols - 1)/ncols; + + for (j = 0; j < nrows; j++) { + pos = tpos = 0; + for (k = i+j; k < endpage; k += nrows) { + pos += printf("%*s%-5s %s", + (tpos - pos), "", + type_str(dex[k]->d_type), + dex[k]->d_name); + tpos += colwidth; + } + printf("\n"); + } + + if (endpage >= n_de) + break; + + get_key(stdin, 0); + } + + 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[]) +{ + int rv; + + if (getscreensize(1, &rows, &cols)) { + /* Unknown screen size? */ + rows = 24; + cols = 80; + } + + if (argc < 2) + rv = display_directory("."); + else if (argc == 2) + rv = display_directory(argv[1]); + else { + printf("Usage: dir directory\n"); + rv = 1; + } + + return rv ? 1 : 0; +} + |