dir2list

generate a list of files shuffled by directory
git clone anongit@rnpnr.xyz:dir2list.git
Log | Files | Refs | Feed | README | LICENSE

dir2list.c (3601B)


      1 #include <dirent.h>
      2 #include <errno.h>
      3 #include <stdarg.h>
      4 #include <stdio.h>
      5 #include <stdint.h>
      6 #include <stdlib.h>
      7 #include <string.h>
      8 #include <sys/stat.h>
      9 #include <time.h>
     10 
     11 #include "config.h"
     12 
     13 /* sqrt(SIZE_MAX + 1): for (a < this; b < this) a * b <= SIZE_MAX */
     14 #define MUL_NO_OVERFLOW (1UL << (sizeof(size_t) * 4))
     15 
     16 struct node {
     17 	char *path;	/* Path containing media files */
     18 	int a;		/* Applied */
     19 };
     20 
     21 /* this makes calls to qsort nicer */
     22 struct entry {
     23 	char *name;
     24 };
     25 
     26 static struct node *nodes;
     27 static struct entry *ents;
     28 
     29 static size_t n_nodes;
     30 static size_t n_ents;
     31 
     32 static void
     33 die(const char *fmt, ...)
     34 {
     35 	va_list ap;
     36 
     37 	va_start(ap, fmt);
     38 	vfprintf(stderr, fmt, ap);
     39 	va_end(ap);
     40 
     41 	exit(1);
     42 }
     43 
     44 static void
     45 usage(const char *argv0)
     46 {
     47 	die("usage: %s [dir]\n", argv0);
     48 }
     49 
     50 static void *
     51 xmalloc(size_t s)
     52 {
     53 	void *p;
     54 
     55 	if (!(p = malloc(s)))
     56 		die("malloc()\n");
     57 
     58 	return p;		
     59 }
     60 
     61 static void *
     62 reallocarray(void *p, size_t n, size_t s)
     63 {
     64 	if ((n >= MUL_NO_OVERFLOW || s >= MUL_NO_OVERFLOW)
     65 	    && n > 0 && SIZE_MAX / n < s)
     66 		die("reallocarray(): Out of Memory\n");
     67 
     68 	return realloc(p, n * s);
     69 }
     70 
     71 static int
     72 entcmp(const void *va, const void *vb)
     73 {
     74 	const struct entry *a = va, *b = vb;
     75 	return strcmp(a->name, b->name);
     76 }
     77 
     78 static int
     79 valid_dir(const char *dir)
     80 {
     81 	if (!strcmp(dir, ".") || !strcmp(dir, ".."))
     82 		return 0;
     83 
     84 	return 1;
     85 }
     86 
     87 static int
     88 valid_file(const char *file)
     89 {
     90 	const char *s, **types;
     91 	types = filetypes;
     92 	for (; *types; types++) {
     93 		s = *types;
     94 		if (strstr(file, s))
     95 			return 1;
     96 	}
     97 	return 0;
     98 }
     99 
    100 static void
    101 addfiles(const char *path)
    102 {
    103 	DIR *dir;
    104 	struct dirent *dent;
    105 	char *s;
    106 	size_t len, n;
    107 
    108 	if (!(dir = opendir(path)))
    109 		die("opendir(): failed to open: %s\n", path);
    110 
    111 	for (n = 0; (dent = readdir(dir));) {
    112 		if (!valid_file(dent->d_name))
    113 			continue;
    114 
    115 		ents = reallocarray(ents, n_ents + 1, sizeof(struct entry));
    116 
    117 		len = strlen(path) + strlen(dent->d_name) + 2;
    118 		s = xmalloc(len);
    119 		snprintf(s, len, "%s/%s", path, dent->d_name);
    120 		ents[n_ents++].name = s;
    121 		n++;
    122 	}
    123 	closedir(dir);
    124 
    125 	qsort(&ents[n_ents - n], n, sizeof(struct entry), entcmp);
    126 }
    127 
    128 /* Fill out the next field for all nodes */
    129 static void
    130 subdir(const char *path)
    131 {
    132 	DIR *dir;
    133 	struct dirent *ent;
    134 	struct stat sb;
    135 	char *s;
    136 	size_t len;
    137 
    138 	if (!(dir = opendir(path)))
    139 		die("opendir(): failed to open: %s\n", path);
    140 
    141 	while ((ent = readdir(dir))) {
    142 		len = strlen(path) + strlen(ent->d_name) + 2;
    143 		s = xmalloc(len);
    144 		len = snprintf(s, len, "%s/%s", path, ent->d_name);
    145 
    146 		stat(s, &sb);
    147 		if (!S_ISDIR(sb.st_mode) || !valid_dir(ent->d_name)) {
    148 			free(s);
    149 			continue;
    150 		}
    151 
    152 		nodes = reallocarray(nodes, n_nodes + 1, sizeof(struct node));
    153 		nodes[n_nodes].path = s;
    154 		nodes[n_nodes].a = 0;
    155 
    156 		/* recurse into subdir */
    157 		subdir(nodes[n_nodes++].path);
    158 	}
    159 	closedir(dir);
    160 }
    161 
    162 static void
    163 mklist(void)
    164 {
    165 	int i, j;
    166 	for (i = 0; i < n_nodes;) {
    167 		j = rand() % n_nodes;
    168 
    169 		if (nodes[j].a)
    170 			continue;
    171 
    172 		addfiles(nodes[j].path);
    173 		nodes[j].a = 1;
    174 		i++;
    175 	}
    176 }
    177 
    178 static void
    179 printlist(void)
    180 {
    181 	int i;
    182 	for (i = 0; i < n_ents; i++)
    183 		fprintf(stdout, "%s\n", ents[i].name);
    184 }
    185 
    186 int
    187 main(int argc, char *argv[])
    188 {
    189 	struct stat sb;
    190 
    191 	if (argc != 2)
    192 		usage(argv[0]);
    193 
    194 	if (stat(argv[1], &sb) != 0 || !S_ISDIR(sb.st_mode)) {
    195 		if (errno == ENOENT && argv[1][0] == '/')
    196 			die("dir: %s: does not exist\n", argv[1]);
    197 		usage(argv[0]);
    198 	}
    199 
    200 	nodes = reallocarray(nodes, ++n_nodes, sizeof(struct node));
    201 
    202 	nodes[0].path = xmalloc(strlen(argv[1]) + 1);
    203 	nodes[0].path = strcpy(nodes[0].path, argv[1]);
    204 	nodes[0].a = 0;
    205 
    206 	srand(time(NULL));
    207 
    208 	subdir(nodes[0].path);
    209 	mklist();
    210 
    211 	printlist();
    212 
    213 	return 0;
    214 }