176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/*
276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Display directory contents
376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */
476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <stdlib.h>
576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <stdio.h>
676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <console.h>
776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <string.h>
876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <com32.h>
976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <dirent.h>
1076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <minmax.h>
1176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <unistd.h>
1276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <getkey.h>
1376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
1476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic int rows, cols;		/* Screen parameters */
1576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
1676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define DIR_CHUNK	1024
1776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
1876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic const char *type_str(int type)
1976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
2076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    switch (type) {
2176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    case DT_FIFO:
2276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	return "[fif]";
2376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    case DT_CHR:
2476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	return "[chr]";
2576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    case DT_DIR:
2676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	return "[dir]";
2776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    case DT_BLK:
2876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	return "[blk]";
2976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    case DT_UNKNOWN:
3076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    case DT_REG:
3176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	return "";
3276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    case DT_LNK:
3376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	return "[lnk]";
3476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    case DT_SOCK:
3576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	return "[sck]";
3676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    case DT_WHT:
3776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	return "[wht]";
3876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    default:
3976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	return "[???]";
4076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    }
4176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
4276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
4376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void free_dirents(struct dirent **dex, size_t n_de)
4476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
4576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    size_t i;
4676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
4776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    for (i = 0; i < n_de; i++)
4876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	free(dex[i]);
4976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
5076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    free(dex);
5176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
5276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
5376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic int compare_dirent(const void *p_de1, const void *p_de2)
5476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
5576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    const struct dirent *de1 = *(const struct dirent **)p_de1;
5676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    const struct dirent *de2 = *(const struct dirent **)p_de2;
5776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    int ndir1, ndir2;
5876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
5976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    ndir1 = de1->d_type != DT_DIR;
6076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    ndir2 = de2->d_type != DT_DIR;
6176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
6276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if (ndir1 != ndir2)
6376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	return ndir1 - ndir2;
6476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
6576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    return strcmp(de1->d_name, de2->d_name);
6676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
6776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
6876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic int display_directory(const char *dirname)
6976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
7076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    DIR *dir;
7176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    struct dirent *de;
7276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    struct dirent **dex = NULL;
7376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    size_t n_dex = 0, n_de = 0;
7476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    size_t i, j, k;
7576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    size_t nrows, ncols, perpage;
7676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    size_t endpage;
7776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    int maxlen = 0;
7876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    int pos, tpos, colwidth;
7976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
8076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    dir = opendir(dirname);
8176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if (!dir) {
8276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	printf("Unable to read directory: %s\n", dirname);
8376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	return -1;
8476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    }
8576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
8676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    while ((de = readdir(dir)) != NULL) {
8776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	struct dirent *nde;
8876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
8976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	if (n_de >= n_dex) {
9076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    struct dirent **ndex;
9176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
9276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    ndex = realloc(dex, (n_dex + DIR_CHUNK) * sizeof *dex);
9376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    if (!ndex)
9476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		goto nomem;
9576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
9676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    dex = ndex;
9776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    n_dex += DIR_CHUNK;
9876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	}
9976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
10076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	nde = malloc(de->d_reclen);
10176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	if (!nde)
10276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    goto nomem;
10376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
10476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	memcpy(nde, de, de->d_reclen);
10576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	dex[n_de++] = nde;
10676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
10776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	maxlen = max(maxlen, de->d_reclen);
10876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    }
10976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
11076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    closedir(dir);
11176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
11276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    qsort(dex, n_de, sizeof *dex, compare_dirent);
11376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
11476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    maxlen -= offsetof(struct dirent, d_name) + 1;
11576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    ncols = (cols + 2)/(maxlen + 8);
11676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    ncols = min(ncols, n_de);
11776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    ncols = max(ncols, 1U);
11876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    colwidth = (cols + 2)/ncols;
11976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    perpage = ncols * (rows - 1);
12076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
12176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    for (i = 0; i < n_de; i += perpage) {
12276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	/* Rows on this page */
12376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	endpage = min(i+perpage, n_de);
12476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	nrows = ((endpage-i) + ncols - 1)/ncols;
12576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
12676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	for (j = 0; j < nrows; j++) {
12776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    pos = tpos = 0;
12876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    for (k = i+j; k < endpage; k += nrows) {
12976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		pos += printf("%*s%-5s %s",
13076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			      (tpos - pos), "",
13176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			      type_str(dex[k]->d_type),
13276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			      dex[k]->d_name);
13376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		tpos += colwidth;
13476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    }
13576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    printf("\n");
13676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	}
13776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
13876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	if (endpage >= n_de)
13976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    break;
14076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
14176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	get_key(stdin, 0);
14276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    }
14376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
14476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    free_dirents(dex, n_de);
14576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    return 0;
14676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
14776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmannomem:
14876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    closedir(dir);
14976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    printf("Out of memory error!\n");
15076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    free_dirents(dex, n_de);
15176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    return -1;
15276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
15376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
15476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanint main(int argc, char *argv[])
15576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
15676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    int rv;
15776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
15876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if (getscreensize(1, &rows, &cols)) {
15976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	/* Unknown screen size? */
16076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	rows = 24;
16176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	cols = 80;
16276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    }
16376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
16476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if (argc < 2)
16576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	rv = display_directory(".");
16676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    else if (argc == 2)
16776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	rv = display_directory(argv[1]);
16876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    else {
16976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	printf("Usage: dir directory\n");
17076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	rv = 1;
17176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    }
17276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
17376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    return rv ? 1 : 0;
17476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
17576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
176