summaryrefslogtreecommitdiff
path: root/src/glob/glob.c
blob: 8a45ed65dc309637837d8eb00a6cbca240cf85ad (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
#if 0

#include <sys/types.h>
#include <glob.h>
#include <stdlib.h>
#include <string.h>
#include <dirent.h>
#include <fnmatch.h>
#include <errno.h>
#include <unistd.h>
#include "_assert.h"

int glob(const char * restrict pattern, int flags, int (*errfunc) (const char * epath, int eerrno), glob_t * restrict pglob)
{
	ASSERT_NONNULL(pattern);
	ASSERT_NONNULL(pglob);

	int slashes = 0;
	size_t i;

	int fnmatch_flags = FNM_PATHNAME | FNM_PERIOD;

	if (flags & GLOB_NOESCAPE) {
		fnmatch_flags |= FNM_NOESCAPE;
	}

	if (flags & GLOB_APPEND) {
		if (pglob->gl_pathc == 0) {
			/* no good */
		}

		if (pglob->gl_offs > 0 && !(flags & GLOB_DOOFFS)) {
			/* nope */
		}
	} else {
		if (pglob->gl_pathc != 0) {
			/* also no */
		}
	}

	char *path = malloc(strlen(pattern) + 1);
	strcpy(path, pattern);

	for (i = 0; path[i]; i++) {
		if (path[i] == '/') {
			slashes++;
			path[i] = '\0';
		}
	}

	if (path[0] == '\0') {
		path[0] = '/';
		slashes--;
	}

	/* TODO: check for trailing slash to match only directories */
	/* TODO: compress adjacent slashes */
	/* TODO: DOOFFS */

	do {
		const char *p = path + strlen(path) + 1;
		struct dirent *de;
		DIR *d = opendir(slashes ? path : ".");
		if (d == NULL) {
			if (errfunc != NULL) {
				if (errfunc(path, errno) != 0) {
					return GLOB_ABORTED;
				}
			}

			if (flags & GLOB_ERR) {
				return GLOB_ABORTED;
			}
		}

		while ((de = readdir(d)) != NULL) {
			if (fnmatch(p, de->d_name, fnmatch_flags) == 0) {
				pglob->gl_pathc++;
				char **tmp = realloc(pglob->gl_pathv, sizeof(char*) * pglob->gl_pathc);
				if (tmp == NULL) {
					pglob->gl_pathc--;
					return GLOB_NOSPACE;
				}

				pglob->gl_pathv = tmp;
				/* FIXME: add path to front */
				pglob->gl_pathv[pglob->gl_pathc - 1] = malloc(strlen(de->d_name) + 1);
				strcat(pglob->gl_pathv[pglob->gl_pathc - 1], de->d_name);
				/* TODO: MARK */
			}
		}

		closedir(d);

		path[strlen(path)] = '/';
		slashes--;
	} while (slashes);

	if (pglob->gl_pathc == 0) {
		if (flags & GLOB_NOCHECK) {
			/* TODO: DOOFFS */
			pglob->gl_pathc = 1;
			pglob->gl_pathv = malloc(sizeof(char*));
			pglob->gl_pathv[0] = malloc(strlen(pattern) + 1);
			strcpy(pglob->gl_pathv[0], pattern);
		} else {
			return GLOB_NOMATCH;
		}
	}

	if (!(flags & GLOB_NOSORT)) {
		qsort(pglob->gl_pathv + pglob->gl_offs, pglob->gl_pathc,
			sizeof(char*),
			(int (*)(const void *, const void *))strcoll);
	}

	return 0;
}

/*
POSIX(2)
*/



#endif