| xf.li | bdd93d5 | 2023-05-12 07:10:14 -0700 | [diff] [blame] | 1 | /* Test the GNU extensions in glob which allow the user to provide callbacks | 
 | 2 |    for the filesystem access functions. | 
 | 3 |    Copyright (C) 2001-2016 Free Software Foundation, Inc. | 
 | 4 |    This file is part of the GNU C Library. | 
 | 5 |    Contributed by Ulrich Drepper <drepper@redhat.com>, 2001. | 
 | 6 |  | 
 | 7 |    The GNU C Library is free software; you can redistribute it and/or | 
 | 8 |    modify it under the terms of the GNU Lesser General Public | 
 | 9 |    License as published by the Free Software Foundation; either | 
 | 10 |    version 2.1 of the License, or (at your option) any later version. | 
 | 11 |  | 
 | 12 |    The GNU C Library is distributed in the hope that it will be useful, | 
 | 13 |    but WITHOUT ANY WARRANTY; without even the implied warranty of | 
 | 14 |    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU | 
 | 15 |    Lesser General Public License for more details. | 
 | 16 |  | 
 | 17 |    You should have received a copy of the GNU Lesser General Public | 
 | 18 |    License along with the GNU C Library; if not, see | 
 | 19 |    <http://www.gnu.org/licenses/>.  */ | 
 | 20 |  | 
 | 21 | #include <dirent.h> | 
 | 22 | #include <errno.h> | 
 | 23 | #include <error.h> | 
 | 24 | #include <glob.h> | 
 | 25 | #include <mcheck.h> | 
 | 26 | #include <stdio.h> | 
 | 27 | #include <stdlib.h> | 
 | 28 | #include <string.h> | 
 | 29 | #include <sys/stat.h> | 
 | 30 |  | 
 | 31 |  | 
 | 32 | // #define DEBUG | 
 | 33 | #ifdef DEBUG | 
 | 34 | # define PRINTF(fmt, args...) printf (fmt, ##args) | 
 | 35 | #else | 
 | 36 | # define PRINTF(fmt, args...) | 
 | 37 | #endif | 
 | 38 |  | 
 | 39 |  | 
 | 40 | static struct | 
 | 41 | { | 
 | 42 |   const char *name; | 
 | 43 |   int level; | 
 | 44 |   int type; | 
 | 45 | } filesystem[] = | 
 | 46 | { | 
 | 47 |   { ".", 1, DT_DIR }, | 
 | 48 |   { "..", 1, DT_DIR }, | 
 | 49 |   { "file1lev1", 1, DT_REG }, | 
 | 50 |   { "file2lev1", 1, DT_UNKNOWN }, | 
 | 51 |   { "dir1lev1", 1, DT_UNKNOWN }, | 
 | 52 |     { ".", 2, DT_DIR }, | 
 | 53 |     { "..", 2, DT_DIR }, | 
 | 54 |     { "file1lev2", 2, DT_REG }, | 
 | 55 |     { "dir1lev2", 2, DT_DIR }, | 
 | 56 |       { ".", 3, DT_DIR }, | 
 | 57 |       { "..", 3, DT_DIR }, | 
 | 58 |     { "dir2lev2", 2, DT_DIR }, | 
 | 59 |       { ".", 3, DT_DIR }, | 
 | 60 |       { "..", 3, DT_DIR }, | 
 | 61 |       { ".foo", 3, DT_REG }, | 
 | 62 |       { "dir1lev3", 3, DT_DIR }, | 
 | 63 | 	{ ".", 4, DT_DIR }, | 
 | 64 | 	{ "..", 4, DT_DIR }, | 
 | 65 | 	{ "file1lev4", 4, DT_REG }, | 
 | 66 |       { "file1lev3", 3, DT_REG }, | 
 | 67 |       { "file2lev3", 3, DT_REG }, | 
 | 68 |     { "file2lev2", 2, DT_REG }, | 
 | 69 |     { "file3lev2", 2, DT_REG }, | 
 | 70 |     { "dir3lev2", 2, DT_DIR }, | 
 | 71 |       { ".", 3, DT_DIR }, | 
 | 72 |       { "..", 3, DT_DIR }, | 
 | 73 |       { "file3lev3", 3, DT_REG }, | 
 | 74 |       { "file4lev3", 3, DT_REG }, | 
 | 75 |   { "dir2lev1", 1, DT_DIR }, | 
 | 76 |     { ".", 2, DT_DIR }, | 
 | 77 |     { "..", 2, DT_DIR }, | 
 | 78 |     { "dir1lev2", 2, DT_UNKNOWN }, | 
 | 79 |       { ".", 3, DT_DIR }, | 
 | 80 |       { "..", 3, DT_DIR }, | 
 | 81 |       { ".foo", 3, DT_REG }, | 
 | 82 |       { ".dir", 3, DT_DIR }, | 
 | 83 | 	{ ".", 4, DT_DIR }, | 
 | 84 | 	{ "..", 4, DT_DIR }, | 
 | 85 | 	{ "hidden", 4, DT_REG } | 
 | 86 | }; | 
 | 87 | #define nfiles (sizeof (filesystem) / sizeof (filesystem[0])) | 
 | 88 |  | 
 | 89 |  | 
 | 90 | typedef struct | 
 | 91 | { | 
 | 92 |   int level; | 
 | 93 |   int idx; | 
 | 94 |   struct dirent d; | 
 | 95 |   char room_for_dirent[NAME_MAX]; | 
 | 96 | } my_DIR; | 
 | 97 |  | 
 | 98 |  | 
 | 99 | static long int | 
 | 100 | find_file (const char *s) | 
 | 101 | { | 
 | 102 |   int level = 1; | 
 | 103 |   long int idx = 0; | 
 | 104 |  | 
 | 105 |   while (s[0] == '/') | 
 | 106 |     { | 
 | 107 |       if (s[1] == '\0') | 
 | 108 | 	{ | 
 | 109 | 	  s = "."; | 
 | 110 | 	  break; | 
 | 111 | 	} | 
 | 112 |       ++s; | 
 | 113 |     } | 
 | 114 |  | 
 | 115 |   if (strcmp (s, ".") == 0) | 
 | 116 |     return 0; | 
 | 117 |  | 
 | 118 |   if (s[0] == '.' && s[1] == '/') | 
 | 119 |     s += 2; | 
 | 120 |  | 
 | 121 |   while (*s != '\0') | 
 | 122 |     { | 
 | 123 |       char *endp = strchrnul (s, '/'); | 
 | 124 |  | 
 | 125 |       PRINTF ("looking for %.*s, level %d\n", (int) (endp - s), s, level); | 
 | 126 |  | 
 | 127 |       while (idx < nfiles && filesystem[idx].level >= level) | 
 | 128 | 	{ | 
 | 129 | 	  if (filesystem[idx].level == level | 
 | 130 | 	      && memcmp (s, filesystem[idx].name, endp - s) == 0 | 
 | 131 | 	      && filesystem[idx].name[endp - s] == '\0') | 
 | 132 | 	    break; | 
 | 133 | 	  ++idx; | 
 | 134 | 	} | 
 | 135 |  | 
 | 136 |       if (idx == nfiles || filesystem[idx].level < level) | 
 | 137 | 	{ | 
 | 138 | 	  errno = ENOENT; | 
 | 139 | 	  return -1; | 
 | 140 | 	} | 
 | 141 |  | 
 | 142 |       if (*endp == '\0') | 
 | 143 | 	return idx + 1; | 
 | 144 |  | 
 | 145 |       if (filesystem[idx].type != DT_DIR | 
 | 146 | 	  && (idx + 1 >= nfiles | 
 | 147 | 	      || filesystem[idx].level >= filesystem[idx + 1].level)) | 
 | 148 | 	{ | 
 | 149 | 	  errno = ENOTDIR; | 
 | 150 | 	  return -1; | 
 | 151 | 	} | 
 | 152 |  | 
 | 153 |       ++idx; | 
 | 154 |  | 
 | 155 |       s = endp + 1; | 
 | 156 |       ++level; | 
 | 157 |     } | 
 | 158 |  | 
 | 159 |   errno = ENOENT; | 
 | 160 |   return -1; | 
 | 161 | } | 
 | 162 |  | 
 | 163 |  | 
 | 164 | static void * | 
 | 165 | my_opendir (const char *s) | 
 | 166 | { | 
 | 167 |   long int idx = find_file (s); | 
 | 168 |   my_DIR *dir; | 
 | 169 |  | 
 | 170 |  | 
 | 171 |   if (idx == -1 || filesystem[idx].type != DT_DIR) | 
 | 172 |     { | 
 | 173 |       PRINTF ("my_opendir(\"%s\") == NULL\n", s); | 
 | 174 |       return NULL; | 
 | 175 |     } | 
 | 176 |  | 
 | 177 |   dir = (my_DIR *) malloc (sizeof (my_DIR)); | 
 | 178 |   if (dir == NULL) | 
 | 179 |     error (EXIT_FAILURE, errno, "cannot allocate directory handle"); | 
 | 180 |  | 
 | 181 |   dir->level = filesystem[idx].level; | 
 | 182 |   dir->idx = idx; | 
 | 183 |  | 
 | 184 |   PRINTF ("my_opendir(\"%s\") == { level: %d, idx: %ld }\n", | 
 | 185 | 	  s, filesystem[idx].level, idx); | 
 | 186 |  | 
 | 187 |   return dir; | 
 | 188 | } | 
 | 189 |  | 
 | 190 |  | 
 | 191 | static struct dirent * | 
 | 192 | my_readdir (void *gdir) | 
 | 193 | { | 
 | 194 |   my_DIR *dir = gdir; | 
 | 195 |  | 
 | 196 |   if (dir->idx == -1) | 
 | 197 |     { | 
 | 198 |       PRINTF ("my_readdir ({ level: %d, idx: %ld }) = NULL\n", | 
 | 199 | 	      dir->level, (long int) dir->idx); | 
 | 200 |       return NULL; | 
 | 201 |     } | 
 | 202 |  | 
 | 203 |   while (dir->idx < nfiles && filesystem[dir->idx].level > dir->level) | 
 | 204 |     ++dir->idx; | 
 | 205 |  | 
 | 206 |   if (dir->idx == nfiles || filesystem[dir->idx].level < dir->level) | 
 | 207 |     { | 
 | 208 |       dir->idx = -1; | 
 | 209 |       PRINTF ("my_readdir ({ level: %d, idx: %ld }) = NULL\n", | 
 | 210 | 	      dir->level, (long int) dir->idx); | 
 | 211 |       return NULL; | 
 | 212 |     } | 
 | 213 |  | 
 | 214 |   dir->d.d_ino = dir->idx; | 
 | 215 |  | 
 | 216 | #ifdef _DIRENT_HAVE_D_TYPE | 
 | 217 |   dir->d.d_type = filesystem[dir->idx].type; | 
 | 218 | #endif | 
 | 219 |  | 
 | 220 |   strcpy (dir->d.d_name, filesystem[dir->idx].name); | 
 | 221 |  | 
 | 222 | #ifdef _DIRENT_HAVE_D_TYPE | 
 | 223 |   PRINTF ("my_readdir ({ level: %d, idx: %ld }) = { d_ino: %ld, d_type: %d, d_name: \"%s\" }\n", | 
 | 224 | 	  dir->level, (long int) dir->idx, dir->d.d_ino, dir->d.d_type, | 
 | 225 | 	  dir->d.d_name); | 
 | 226 | #else | 
 | 227 |   PRINTF ("my_readdir ({ level: %d, idx: %ld }) = { d_ino: %ld, d_name: \"%s\" }\n", | 
 | 228 | 	  dir->level, (long int) dir->idx, dir->d.d_ino, | 
 | 229 | 	  dir->d.d_name); | 
 | 230 | #endif | 
 | 231 |  | 
 | 232 |   ++dir->idx; | 
 | 233 |  | 
 | 234 |   return &dir->d; | 
 | 235 | } | 
 | 236 |  | 
 | 237 |  | 
 | 238 | static void | 
 | 239 | my_closedir (void *dir) | 
 | 240 | { | 
 | 241 |   PRINTF ("my_closedir ()\n"); | 
 | 242 |   free (dir); | 
 | 243 | } | 
 | 244 |  | 
 | 245 |  | 
 | 246 | /* We use this function for lstat as well since we don't have any.  */ | 
 | 247 | static int | 
 | 248 | my_stat (const char *name, struct stat *st) | 
 | 249 | { | 
 | 250 |   long int idx = find_file (name); | 
 | 251 |  | 
 | 252 |   if (idx == -1) | 
 | 253 |     { | 
 | 254 |       PRINTF ("my_stat (\"%s\", ...) = -1 (%s)\n", name, strerror (errno)); | 
 | 255 |       return -1; | 
 | 256 |     } | 
 | 257 |  | 
 | 258 |   memset (st, '\0', sizeof (*st)); | 
 | 259 |  | 
 | 260 |   if (filesystem[idx].type == DT_UNKNOWN) | 
 | 261 |     st->st_mode = DTTOIF (idx + 1 < nfiles | 
 | 262 | 			  && filesystem[idx].level < filesystem[idx + 1].level | 
 | 263 | 			  ? DT_DIR : DT_REG) | 0777; | 
 | 264 |   else | 
 | 265 |     st->st_mode = DTTOIF (filesystem[idx].type) | 0777; | 
 | 266 |  | 
 | 267 |   PRINTF ("my_stat (\"%s\", { st_mode: %o }) = 0\n", name, st->st_mode); | 
 | 268 |  | 
 | 269 |   return 0; | 
 | 270 | } | 
 | 271 |  | 
 | 272 |  | 
 | 273 | static const char *glob_errstring[] = | 
 | 274 | { | 
 | 275 |   [GLOB_NOSPACE] = "out of memory", | 
 | 276 |   [GLOB_ABORTED] = "read error", | 
 | 277 |   [GLOB_NOMATCH] = "no matches found" | 
 | 278 | }; | 
 | 279 | #define nglob_errstring (sizeof (glob_errstring) / sizeof (glob_errstring[0])) | 
 | 280 |  | 
 | 281 |  | 
 | 282 | static const char * | 
 | 283 | flagstr (int flags) | 
 | 284 | { | 
 | 285 |   static const char *const strs[] = | 
 | 286 |   { | 
 | 287 |     "GLOB_ERR", "GLOB_MARK", "GLOB_NOSORT", "GLOB_DOOFSS", "GLOB_NOCHECK", | 
 | 288 |     "GLOB_APPEND", "GLOB_NOESCAPE", "GLOB_PERIOD", "GLOB_MAGCHAR", | 
 | 289 |     "GLOB_ALTDIRFUNC", "GLOB_BRACE", "GLOB_NOMAGIC", "GLOB_TILDE", | 
 | 290 |     "GLOB_ONLYDIR", "GLOB_TILDECHECK" | 
 | 291 |   }; | 
 | 292 | #define nstrs (sizeof (strs) / sizeof (strs[0])) | 
 | 293 |   static char buf[100]; | 
 | 294 |   char *cp = buf; | 
 | 295 |   int cnt; | 
 | 296 |  | 
 | 297 |   for (cnt = 0; cnt < nstrs; ++cnt) | 
 | 298 |     if (flags & (1 << cnt)) | 
 | 299 |       { | 
 | 300 | 	flags &= ~(1 << cnt); | 
 | 301 | 	if (cp != buf) | 
 | 302 | 	  *cp++ = '|'; | 
 | 303 | 	cp = stpcpy (cp, strs[cnt]); | 
 | 304 |       } | 
 | 305 |  | 
 | 306 |   if (flags != 0) | 
 | 307 |     { | 
 | 308 |       if (cp != buf) | 
 | 309 | 	*cp++ = '|'; | 
 | 310 |       sprintf (cp, "%#x", flags); | 
 | 311 |     } | 
 | 312 |  | 
 | 313 |   return buf; | 
 | 314 | #undef nstrs | 
 | 315 | } | 
 | 316 |  | 
 | 317 |  | 
 | 318 | static const char * | 
 | 319 | errstr (int val) | 
 | 320 | { | 
 | 321 |   static const char *const strs[] = | 
 | 322 |     { | 
 | 323 |       [GLOB_NOSPACE] = "GLOB_NOSPACE", | 
 | 324 |       [GLOB_ABORTED] = "GLOB_ABORTED", | 
 | 325 |       [GLOB_NOMATCH] = "GLOB_NOMATCH", | 
 | 326 |       [GLOB_NOSYS] = "GLOB_NOSYS" | 
 | 327 |     }; | 
 | 328 | #define nstrs (sizeof (strs) / sizeof (strs[0])) | 
 | 329 |   static char buf[100]; | 
 | 330 |   if (val < 0 || val >= nstrs || strs[val] == NULL) | 
 | 331 |     { | 
 | 332 |       snprintf (buf, sizeof (buf), "GLOB_??? (%d)", val); | 
 | 333 |       return buf; | 
 | 334 |     } | 
 | 335 |   return strs[val]; | 
 | 336 | #undef nstrs | 
 | 337 | } | 
 | 338 |  | 
 | 339 |  | 
 | 340 | static int | 
 | 341 | test_result (const char *fmt, int flags, glob_t *gl, const char *str[]) | 
 | 342 | { | 
 | 343 |   size_t cnt; | 
 | 344 |   int result = 0; | 
 | 345 |  | 
 | 346 |   printf ("results for glob (\"%s\", %s)\n", fmt, flagstr (flags)); | 
 | 347 |   for (cnt = 0; cnt < gl->gl_pathc && str[cnt] != NULL; ++cnt) | 
 | 348 |     { | 
 | 349 |       int ok = strcmp (gl->gl_pathv[cnt], str[cnt]) == 0; | 
 | 350 |       const char *errstr = ""; | 
 | 351 |  | 
 | 352 |       if (! ok) | 
 | 353 | 	{ | 
 | 354 | 	  size_t inner; | 
 | 355 |  | 
 | 356 | 	  for (inner = 0; str[inner] != NULL; ++inner) | 
 | 357 | 	    if (strcmp (gl->gl_pathv[cnt], str[inner]) == 0) | 
 | 358 | 	      break; | 
 | 359 |  | 
 | 360 | 	  if (str[inner] == NULL) | 
 | 361 | 	    errstr = ok ? "" : " *** WRONG"; | 
 | 362 | 	  else | 
 | 363 | 	    errstr = ok ? "" : " * wrong position"; | 
 | 364 |  | 
 | 365 | 	  result = 1; | 
 | 366 | 	} | 
 | 367 |  | 
 | 368 |       printf ("  %s%s\n", gl->gl_pathv[cnt], errstr); | 
 | 369 |     } | 
 | 370 |   puts (""); | 
 | 371 |  | 
 | 372 |   if (str[cnt] != NULL || cnt < gl->gl_pathc) | 
 | 373 |     { | 
 | 374 |       puts ("  *** incorrect number of entries"); | 
 | 375 |       result = 1; | 
 | 376 |     } | 
 | 377 |  | 
 | 378 |   return result; | 
 | 379 | } | 
 | 380 |  | 
 | 381 |  | 
 | 382 | static int | 
 | 383 | do_test (void) | 
 | 384 | { | 
 | 385 |   glob_t gl; | 
 | 386 |   int errval; | 
 | 387 |   int result = 0; | 
 | 388 |   const char *fmt; | 
 | 389 |   int flags; | 
 | 390 |  | 
 | 391 |   mtrace (); | 
 | 392 |  | 
 | 393 |   memset (&gl, '\0', sizeof (gl)); | 
 | 394 |  | 
 | 395 |   gl.gl_closedir = my_closedir; | 
 | 396 |   gl.gl_readdir = my_readdir; | 
 | 397 |   gl.gl_opendir = my_opendir; | 
 | 398 |   gl.gl_lstat = my_stat; | 
 | 399 |   gl.gl_stat = my_stat; | 
 | 400 |  | 
 | 401 | #define test(a, b, r, c...) \ | 
 | 402 |   fmt = a;								      \ | 
 | 403 |   flags = GLOB_ALTDIRFUNC | b;						      \ | 
 | 404 |   errval = glob (fmt, flags, NULL, &gl);				      \ | 
 | 405 |   if (errval != r)							      \ | 
 | 406 |     {									      \ | 
 | 407 |       if (r == 0)							      \ | 
 | 408 | 	printf ("glob (\"%s\", %s) failed: %s\n", fmt, flagstr (flags),	      \ | 
 | 409 | 		errval >= 0 && errval < nglob_errstring			      \ | 
 | 410 | 		? glob_errstring[errval] : "???");			      \ | 
 | 411 |       else								      \ | 
 | 412 | 	printf ("glob (\"%s\", %s) did not fail\n", fmt, flagstr (flags));    \ | 
 | 413 |       result = 1;							      \ | 
 | 414 |     }									      \ | 
 | 415 |   else if (r == 0)							      \ | 
 | 416 |     result |= test_result (fmt, flags, &gl, (const char *[]) { c, NULL });    \ | 
 | 417 |   else									      \ | 
 | 418 |     printf ("result for glob (\"%s\", %s) = %s\n\n", fmt, flagstr (flags),    \ | 
 | 419 | 	    errstr (errval)) | 
 | 420 |  | 
 | 421 |   test ("*/*/*", 0, 0, | 
 | 422 | 	"dir1lev1/dir2lev2/dir1lev3", | 
 | 423 | 	"dir1lev1/dir2lev2/file1lev3", | 
 | 424 | 	"dir1lev1/dir2lev2/file2lev3", | 
 | 425 | 	"dir1lev1/dir3lev2/file3lev3", | 
 | 426 | 	"dir1lev1/dir3lev2/file4lev3"); | 
 | 427 |  | 
 | 428 |   test ("*/*/*", GLOB_PERIOD, 0, | 
 | 429 | 	"dir1lev1/dir1lev2/.", | 
 | 430 | 	"dir1lev1/dir1lev2/..", | 
 | 431 | 	"dir1lev1/dir2lev2/.", | 
 | 432 | 	"dir1lev1/dir2lev2/..", | 
 | 433 | 	"dir1lev1/dir2lev2/.foo", | 
 | 434 | 	"dir1lev1/dir2lev2/dir1lev3", | 
 | 435 | 	"dir1lev1/dir2lev2/file1lev3", | 
 | 436 | 	"dir1lev1/dir2lev2/file2lev3", | 
 | 437 | 	"dir1lev1/dir3lev2/.", | 
 | 438 | 	"dir1lev1/dir3lev2/..", | 
 | 439 | 	"dir1lev1/dir3lev2/file3lev3", | 
 | 440 | 	"dir1lev1/dir3lev2/file4lev3", | 
 | 441 | 	"dir2lev1/dir1lev2/.", | 
 | 442 | 	"dir2lev1/dir1lev2/..", | 
 | 443 | 	"dir2lev1/dir1lev2/.dir", | 
 | 444 | 	"dir2lev1/dir1lev2/.foo"); | 
 | 445 |  | 
 | 446 |   test ("*/*/.*", 0, 0, | 
 | 447 | 	"dir1lev1/dir1lev2/.", | 
 | 448 | 	"dir1lev1/dir1lev2/..", | 
 | 449 | 	"dir1lev1/dir2lev2/.", | 
 | 450 | 	"dir1lev1/dir2lev2/..", | 
 | 451 | 	"dir1lev1/dir2lev2/.foo", | 
 | 452 | 	"dir1lev1/dir3lev2/.", | 
 | 453 | 	"dir1lev1/dir3lev2/..", | 
 | 454 | 	"dir2lev1/dir1lev2/.", | 
 | 455 | 	"dir2lev1/dir1lev2/..", | 
 | 456 | 	"dir2lev1/dir1lev2/.dir", | 
 | 457 | 	"dir2lev1/dir1lev2/.foo"); | 
 | 458 |  | 
 | 459 |   test ("*1*/*2*/.*", 0, 0, | 
 | 460 | 	"dir1lev1/dir1lev2/.", | 
 | 461 | 	"dir1lev1/dir1lev2/..", | 
 | 462 | 	"dir1lev1/dir2lev2/.", | 
 | 463 | 	"dir1lev1/dir2lev2/..", | 
 | 464 | 	"dir1lev1/dir2lev2/.foo", | 
 | 465 | 	"dir1lev1/dir3lev2/.", | 
 | 466 | 	"dir1lev1/dir3lev2/..", | 
 | 467 | 	"dir2lev1/dir1lev2/.", | 
 | 468 | 	"dir2lev1/dir1lev2/..", | 
 | 469 | 	"dir2lev1/dir1lev2/.dir", | 
 | 470 | 	"dir2lev1/dir1lev2/.foo"); | 
 | 471 |  | 
 | 472 |   test ("*1*/*1*/.*", 0, 0, | 
 | 473 | 	"dir1lev1/dir1lev2/.", | 
 | 474 | 	"dir1lev1/dir1lev2/..", | 
 | 475 | 	"dir2lev1/dir1lev2/.", | 
 | 476 | 	"dir2lev1/dir1lev2/..", | 
 | 477 | 	"dir2lev1/dir1lev2/.dir", | 
 | 478 | 	"dir2lev1/dir1lev2/.foo"); | 
 | 479 |  | 
 | 480 |   test ("\\/*", 0, 0, | 
 | 481 | 	"/dir1lev1", | 
 | 482 | 	"/dir2lev1", | 
 | 483 | 	"/file1lev1", | 
 | 484 | 	"/file2lev1"); | 
 | 485 |  | 
 | 486 |   test ("*/*/", 0 , 0, | 
 | 487 | 	"dir1lev1/dir1lev2/", | 
 | 488 | 	"dir1lev1/dir2lev2/", | 
 | 489 | 	"dir1lev1/dir3lev2/", | 
 | 490 | 	"dir2lev1/dir1lev2/"); | 
 | 491 |  | 
 | 492 |   test ("", 0, GLOB_NOMATCH, NULL); | 
 | 493 |  | 
 | 494 |   test ("", GLOB_NOCHECK, 0, ""); | 
 | 495 |  | 
 | 496 |   globfree (&gl); | 
 | 497 |  | 
 | 498 |   return result; | 
 | 499 | } | 
 | 500 |  | 
 | 501 | #define TEST_FUNCTION do_test () | 
 | 502 | #include "../test-skeleton.c" |