1272343Sngie/*	$NetBSD: t_glob.c,v 1.3 2013/01/02 11:28:48 martin Exp $	*/
2272343Sngie/*-
3272343Sngie * Copyright (c) 2010 The NetBSD Foundation, Inc.
4272343Sngie * All rights reserved.
5272343Sngie *
6272343Sngie * This code is derived from software contributed to The NetBSD Foundation
7272343Sngie * by Christos Zoulas
8272343Sngie *
9272343Sngie * Redistribution and use in source and binary forms, with or without
10272343Sngie * modification, are permitted provided that the following conditions
11272343Sngie * are met:
12272343Sngie *
13272343Sngie * 1. Redistributions of source code must retain the above copyright
14272343Sngie *    notice, this list of conditions and the following disclaimer.
15272343Sngie * 2. Redistributions in binary form must reproduce the above copyright
16272343Sngie *    notice, this list of conditions and the following disclaimer in
17272343Sngie *    the documentation and/or other materials provided with the
18272343Sngie *    distribution.
19272343Sngie *
20272343Sngie * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21272343Sngie * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22272343Sngie * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23272343Sngie * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
24272343Sngie * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25272343Sngie * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
26272343Sngie * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27272343Sngie * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
28272343Sngie * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
29272343Sngie * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
30272343Sngie * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31272343Sngie * SUCH DAMAGE.
32272343Sngie */
33272343Sngie
34272343Sngie#include <sys/cdefs.h>
35272343Sngie__RCSID("$NetBSD: t_glob.c,v 1.3 2013/01/02 11:28:48 martin Exp $");
36272343Sngie
37272343Sngie#include <atf-c.h>
38272343Sngie
39272343Sngie#include <sys/param.h>
40272343Sngie#include <sys/stat.h>
41272343Sngie
42272343Sngie#include <dirent.h>
43272343Sngie#include <glob.h>
44272343Sngie#include <stdio.h>
45272343Sngie#include <stdlib.h>
46272343Sngie#include <string.h>
47272343Sngie#include <errno.h>
48272343Sngie
49274626Sngie#ifdef __FreeBSD__
50272915Sngie#include "h_macros.h"
51272915Sngie#define	__gl_stat_t struct stat
52272915Sngie#define	_S_IFDIR S_IFDIR
53272915Sngie#else
54272343Sngie#include "../../../h_macros.h"
55272915Sngie#endif
56272343Sngie
57272343Sngie
58272343Sngie#ifdef DEBUG
59272343Sngie#define DPRINTF(a) printf a
60272343Sngie#else
61272343Sngie#define DPRINTF(a)
62272343Sngie#endif
63272343Sngie
64272343Sngiestruct gl_file {
65272343Sngie	const char *name;
66272343Sngie	int dir;
67272343Sngie};
68272343Sngie
69272343Sngiestatic struct gl_file a[] = {
70272343Sngie	{ "1", 0 },
71272343Sngie	{ "b", 1 },
72272343Sngie	{ "3", 0 },
73272343Sngie	{ "4", 0 },
74272343Sngie};
75272343Sngie
76272343Sngiestatic struct gl_file b[] = {
77272343Sngie	{ "x", 0 },
78272343Sngie	{ "y", 0 },
79272343Sngie	{ "z", 0 },
80272343Sngie	{ "w", 0 },
81272343Sngie};
82272343Sngie
83272343Sngiestruct gl_dir {
84272343Sngie	const char *name;	/* directory name */
85272343Sngie	const struct gl_file *dir;
86272343Sngie	size_t len, pos;
87272343Sngie};
88272343Sngie
89272343Sngiestatic struct gl_dir d[] = {
90272343Sngie	{ "a", a, __arraycount(a), 0 },
91272343Sngie	{ "a/b", b, __arraycount(b), 0 },
92272343Sngie};
93272343Sngie
94290847Sngie#ifndef __FreeBSD__
95272343Sngiestatic const char *glob_star[] = {
96272343Sngie    "a/1", "a/3", "a/4", "a/b", "a/b/w", "a/b/x", "a/b/y", "a/b/z",
97272343Sngie};
98290847Sngie#endif
99272343Sngie
100272343Sngiestatic const char *glob_star_not[] = {
101272343Sngie	"a/1", "a/3", "a/4", "a/b",
102272343Sngie};
103272343Sngie
104272343Sngiestatic void
105272343Sngietrim(char *buf, size_t len, const char *name)
106272343Sngie{
107272343Sngie	char *path = buf, *epath = buf + len;
108272343Sngie	while (path < epath && (*path++ = *name++) != '\0')
109272343Sngie		continue;
110272343Sngie	path--;
111272343Sngie	while (path > buf && *--path == '/')
112272343Sngie		*path = '\0';
113272343Sngie}
114272343Sngie
115272343Sngiestatic void *
116272343Sngiegl_opendir(const char *dir)
117272343Sngie{
118272343Sngie	size_t i;
119272343Sngie	char buf[MAXPATHLEN];
120272343Sngie	trim(buf, sizeof(buf), dir);
121272343Sngie
122272343Sngie	for (i = 0; i < __arraycount(d); i++)
123272343Sngie		if (strcmp(buf, d[i].name) == 0) {
124272343Sngie			DPRINTF(("opendir %s %zu\n", buf, i));
125272343Sngie			return &d[i];
126272343Sngie		}
127272343Sngie	errno = ENOENT;
128272343Sngie	return NULL;
129272343Sngie}
130272343Sngie
131272343Sngiestatic struct dirent *
132272343Sngiegl_readdir(void *v)
133272343Sngie{
134272343Sngie	static struct dirent dir;
135272343Sngie	struct gl_dir *dd = v;
136272343Sngie	if (dd->pos < dd->len) {
137272343Sngie		const struct gl_file *f = &dd->dir[dd->pos++];
138272343Sngie		strcpy(dir.d_name, f->name);
139272343Sngie		dir.d_namlen = strlen(f->name);
140272343Sngie		dir.d_ino = dd->pos;
141272343Sngie		dir.d_type = f->dir ? DT_DIR : DT_REG;
142272343Sngie		DPRINTF(("readdir %s %d\n", dir.d_name, dir.d_type));
143274626Sngie#ifdef __FreeBSD__
144272915Sngie		dir.d_reclen = -1; /* Does not have _DIRENT_RECLEN */
145272915Sngie#else
146272343Sngie		dir.d_reclen = _DIRENT_RECLEN(&dir, dir.d_namlen);
147272915Sngie#endif
148272343Sngie		return &dir;
149272343Sngie	}
150272343Sngie	return NULL;
151272343Sngie}
152272343Sngie
153272343Sngiestatic int
154272343Sngiegl_stat(const char *name , __gl_stat_t *st)
155272343Sngie{
156272343Sngie	char buf[MAXPATHLEN];
157272343Sngie	trim(buf, sizeof(buf), name);
158272343Sngie	memset(st, 0, sizeof(*st));
159272343Sngie
160272343Sngie	if (strcmp(buf, "a") == 0 || strcmp(buf, "a/b") == 0) {
161272343Sngie		st->st_mode |= _S_IFDIR;
162272343Sngie		return 0;
163272343Sngie	}
164272343Sngie
165272343Sngie	if (buf[0] == 'a' && buf[1] == '/') {
166272343Sngie		struct gl_file *f;
167272343Sngie		size_t offs, count;
168272343Sngie
169272343Sngie		if (buf[2] == 'b' && buf[3] == '/') {
170272343Sngie			offs = 4;
171272343Sngie			count = __arraycount(b);
172272343Sngie			f = b;
173272343Sngie		} else {
174272343Sngie			offs = 2;
175272343Sngie			count = __arraycount(a);
176272343Sngie			f = a;
177272343Sngie		}
178272343Sngie
179272343Sngie		for (size_t i = 0; i < count; i++)
180272343Sngie			if (strcmp(f[i].name, buf + offs) == 0)
181272343Sngie				return 0;
182272343Sngie	}
183272343Sngie	DPRINTF(("stat %s %d\n", buf, st->st_mode));
184272343Sngie	errno = ENOENT;
185272343Sngie	return -1;
186272343Sngie}
187272343Sngie
188272343Sngiestatic int
189272343Sngiegl_lstat(const char *name , __gl_stat_t *st)
190272343Sngie{
191272343Sngie	return gl_stat(name, st);
192272343Sngie}
193272343Sngie
194272343Sngiestatic void
195272343Sngiegl_closedir(void *v)
196272343Sngie{
197272343Sngie	struct gl_dir *dd = v;
198272343Sngie	dd->pos = 0;
199272343Sngie	DPRINTF(("closedir %p\n", dd));
200272343Sngie}
201272343Sngie
202272343Sngiestatic void
203272343Sngierun(const char *p, int flags, const char **res, size_t len)
204272343Sngie{
205272343Sngie	glob_t gl;
206272343Sngie	size_t i;
207272343Sngie
208272343Sngie	memset(&gl, 0, sizeof(gl));
209272343Sngie	gl.gl_opendir = gl_opendir;
210272343Sngie	gl.gl_readdir = gl_readdir;
211272343Sngie	gl.gl_closedir = gl_closedir;
212272343Sngie	gl.gl_stat = gl_stat;
213272343Sngie	gl.gl_lstat = gl_lstat;
214272343Sngie
215272343Sngie	RZ(glob(p, GLOB_ALTDIRFUNC | flags, NULL, &gl));
216272343Sngie
217272343Sngie	for (i = 0; i < gl.gl_pathc; i++)
218272343Sngie		DPRINTF(("%s\n", gl.gl_pathv[i]));
219272343Sngie
220272343Sngie	ATF_CHECK(len == gl.gl_pathc);
221272343Sngie	for (i = 0; i < gl.gl_pathc; i++)
222272343Sngie		ATF_CHECK_STREQ(gl.gl_pathv[i], res[i]);
223272343Sngie
224272343Sngie	globfree(&gl);
225272343Sngie}
226272343Sngie
227272343Sngie
228274626Sngie#ifndef __FreeBSD__
229272343SngieATF_TC(glob_star);
230272343SngieATF_TC_HEAD(glob_star, tc)
231272343Sngie{
232272343Sngie	atf_tc_set_md_var(tc, "descr",
233272343Sngie	    "Test glob(3) ** with GLOB_STAR");
234272343Sngie}
235272343Sngie
236272343SngieATF_TC_BODY(glob_star, tc)
237272343Sngie{
238272343Sngie	run("a/**", GLOB_STAR, glob_star, __arraycount(glob_star));
239272343Sngie}
240272915Sngie#endif
241272343Sngie
242272343SngieATF_TC(glob_star_not);
243272343SngieATF_TC_HEAD(glob_star_not, tc)
244272343Sngie{
245272343Sngie	atf_tc_set_md_var(tc, "descr",
246272343Sngie	    "Test glob(3) ** without GLOB_STAR");
247272343Sngie}
248272343Sngie
249272343Sngie
250272343SngieATF_TC_BODY(glob_star_not, tc)
251272343Sngie{
252272343Sngie	run("a/**", 0, glob_star_not, __arraycount(glob_star_not));
253272343Sngie}
254272343Sngie
255272343Sngie#if 0
256272343SngieATF_TC(glob_nocheck);
257272343SngieATF_TC_HEAD(glob_nocheck, tc)
258272343Sngie{
259272343Sngie	atf_tc_set_md_var(tc, "descr",
260272343Sngie	    "Test glob(3) pattern with backslash and GLOB_NOCHECK");
261272343Sngie}
262272343Sngie
263272343Sngie
264272343SngieATF_TC_BODY(glob_nocheck, tc)
265272343Sngie{
266272343Sngie	static const char pattern[] = { 'f', 'o', 'o', '\\', ';', 'b', 'a',
267272343Sngie	    'r', '\0' };
268272343Sngie	static const char *glob_nocheck[] = {
269272343Sngie	    pattern
270272343Sngie	};
271272343Sngie	run(pattern, GLOB_NOCHECK, glob_nocheck, __arraycount(glob_nocheck));
272272343Sngie}
273272343Sngie#endif
274272343Sngie
275272343SngieATF_TP_ADD_TCS(tp)
276272343Sngie{
277274626Sngie#ifndef __FreeBSD__
278272343Sngie	ATF_TP_ADD_TC(tp, glob_star);
279272915Sngie#endif
280272343Sngie	ATF_TP_ADD_TC(tp, glob_star_not);
281272343Sngie/*
282272343Sngie * Remove this test for now - the GLOB_NOCHECK return value has been
283272343Sngie * re-defined to return a modified pattern in revision 1.33 of glob.c
284272343Sngie *
285272343Sngie *	ATF_TP_ADD_TC(tp, glob_nocheck);
286272343Sngie */
287272343Sngie
288272343Sngie	return atf_no_error();
289272343Sngie}
290