176 lines
3.2 KiB
C
176 lines
3.2 KiB
C
/*
|
|
* 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;
|
|
}
|
|
|