1 /*
2 * Display directory contents
3 */
4 #include <stdlib.h>
5 #include <stdio.h>
6 #include <console.h>
7 #include <string.h>
8 #include <com32.h>
9 #include <dirent.h>
10 #include <minmax.h>
11 #include <unistd.h>
12 #include <getkey.h>
13
14 static int rows, cols; /* Screen parameters */
15
16 #define DIR_CHUNK 1024
17
type_str(int type)18 static const char *type_str(int type)
19 {
20 switch (type) {
21 case DT_FIFO:
22 return "[fif]";
23 case DT_CHR:
24 return "[chr]";
25 case DT_DIR:
26 return "[dir]";
27 case DT_BLK:
28 return "[blk]";
29 case DT_UNKNOWN:
30 case DT_REG:
31 return "";
32 case DT_LNK:
33 return "[lnk]";
34 case DT_SOCK:
35 return "[sck]";
36 case DT_WHT:
37 return "[wht]";
38 default:
39 return "[???]";
40 }
41 }
42
free_dirents(struct dirent ** dex,size_t n_de)43 static void free_dirents(struct dirent **dex, size_t n_de)
44 {
45 size_t i;
46
47 for (i = 0; i < n_de; i++)
48 free(dex[i]);
49
50 free(dex);
51 }
52
compare_dirent(const void * p_de1,const void * p_de2)53 static int compare_dirent(const void *p_de1, const void *p_de2)
54 {
55 const struct dirent *de1 = *(const struct dirent **)p_de1;
56 const struct dirent *de2 = *(const struct dirent **)p_de2;
57 int ndir1, ndir2;
58
59 ndir1 = de1->d_type != DT_DIR;
60 ndir2 = de2->d_type != DT_DIR;
61
62 if (ndir1 != ndir2)
63 return ndir1 - ndir2;
64
65 return strcmp(de1->d_name, de2->d_name);
66 }
67
display_directory(const char * dirname)68 static int display_directory(const char *dirname)
69 {
70 DIR *dir;
71 struct dirent *de;
72 struct dirent **dex = NULL;
73 size_t n_dex = 0, n_de = 0;
74 size_t i, j, k;
75 size_t nrows, ncols, perpage;
76 size_t endpage;
77 int maxlen = 0;
78 int pos, tpos, colwidth;
79
80 dir = opendir(dirname);
81 if (!dir) {
82 printf("Unable to read directory: %s\n", dirname);
83 return -1;
84 }
85
86 while ((de = readdir(dir)) != NULL) {
87 struct dirent *nde;
88
89 if (n_de >= n_dex) {
90 struct dirent **ndex;
91
92 ndex = realloc(dex, (n_dex + DIR_CHUNK) * sizeof *dex);
93 if (!ndex)
94 goto nomem;
95
96 dex = ndex;
97 n_dex += DIR_CHUNK;
98 }
99
100 nde = malloc(de->d_reclen);
101 if (!nde)
102 goto nomem;
103
104 memcpy(nde, de, de->d_reclen);
105 dex[n_de++] = nde;
106
107 maxlen = max(maxlen, de->d_reclen);
108 }
109
110 closedir(dir);
111
112 qsort(dex, n_de, sizeof *dex, compare_dirent);
113
114 maxlen -= offsetof(struct dirent, d_name) + 1;
115 ncols = (cols + 2)/(maxlen + 8);
116 ncols = min(ncols, n_de);
117 ncols = max(ncols, 1U);
118 colwidth = (cols + 2)/ncols;
119 perpage = ncols * (rows - 1);
120
121 for (i = 0; i < n_de; i += perpage) {
122 /* Rows on this page */
123 endpage = min(i+perpage, n_de);
124 nrows = ((endpage-i) + ncols - 1)/ncols;
125
126 for (j = 0; j < nrows; j++) {
127 pos = tpos = 0;
128 for (k = i+j; k < endpage; k += nrows) {
129 pos += printf("%*s%-5s %s",
130 (tpos - pos), "",
131 type_str(dex[k]->d_type),
132 dex[k]->d_name);
133 tpos += colwidth;
134 }
135 printf("\n");
136 }
137
138 if (endpage >= n_de)
139 break;
140
141 get_key(stdin, 0);
142 }
143
144 free_dirents(dex, n_de);
145 return 0;
146
147 nomem:
148 closedir(dir);
149 printf("Out of memory error!\n");
150 free_dirents(dex, n_de);
151 return -1;
152 }
153
main(int argc,char * argv[])154 int main(int argc, char *argv[])
155 {
156 int rv;
157
158 if (getscreensize(1, &rows, &cols)) {
159 /* Unknown screen size? */
160 rows = 24;
161 cols = 80;
162 }
163
164 if (argc < 2)
165 rv = display_directory(".");
166 else if (argc == 2)
167 rv = display_directory(argv[1]);
168 else {
169 printf("Usage: dir directory\n");
170 rv = 1;
171 }
172
173 return rv ? 1 : 0;
174 }
175
176