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 14static int rows, cols; /* Screen parameters */ 15 16#define DIR_CHUNK 1024 17 18static 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 43static 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 53static 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 68static 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 147nomem: 148 closedir(dir); 149 printf("Out of memory error!\n"); 150 free_dirents(dex, n_de); 151 return -1; 152} 153 154int 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