3 /* Copyright (C) 1991,92,93,94,95,96,97,98,99 Free Software Foundation, Inc.
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public License as
7 published by the Free Software Foundation; either version 2 of the
8 License, or (at your option) any later version.
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Library General Public License for more details.
15 You should have received a copy of the GNU Library General Public
16 License along with this library; see the file COPYING.LIB. If not,
17 write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA. */
20 /* AIX requires this to be the first thing in the file. */
21 #if defined _AIX && !defined __GNUC__
31 #include <sys/stat.h> /* S_ISDIR */
33 /* Bits set in the FLAGS argument to `glob'. */
34 #define GLOB_ERR (1 << 0) /* Return on read errors. */
35 #define GLOB_MARK (1 << 1) /* Append a slash to each name. */
36 #define GLOB_NOSORT (1 << 2) /* Don't sort the names. */
37 #define GLOB_DOOFFS (1 << 3) /* Insert PGLOB->gl_offs NULLs. */
38 #define GLOB_NOCHECK (1 << 4) /* If nothing matches, return the pattern. */
39 #define GLOB_APPEND (1 << 5) /* Append to results of a previous call. */
40 #define GLOB_NOESCAPE (1 << 6) /* Backslashes don't quote metacharacters. */
41 #define GLOB_PERIOD (1 << 7) /* Leading `.' can be matched by metachars. */
43 #define GLOB_MAGCHAR (1 << 8) /* Set in gl_flags if any metachars seen. */
44 #define GLOB_ALTDIRFUNC (1 << 9) /* Use gl_opendir et al functions. */
45 #define GLOB_BRACE (1 << 10) /* Expand "{a,b}" to "a" "b". */
46 #define GLOB_NOMAGIC (1 << 11) /* If no magic chars, return the pattern. */
47 #define GLOB_TILDE (1 << 12) /* Expand ~user and ~ to home directories. */
48 #define GLOB_ONLYDIR (1 << 13) /* Match only directories. */
49 #define GLOB_TILDE_CHECK (1 << 14) /* Like GLOB_TILDE but return an error
50 if the user name is not available. */
51 #define __GLOB_FLAGS (GLOB_ERR|GLOB_MARK|GLOB_NOSORT|GLOB_DOOFFS| \
52 GLOB_NOESCAPE|GLOB_NOCHECK|GLOB_APPEND| \
53 GLOB_PERIOD|GLOB_ALTDIRFUNC|GLOB_BRACE| \
54 GLOB_NOMAGIC|GLOB_TILDE|GLOB_ONLYDIR|GLOB_TILDE_CHECK)
56 /* Error returns from `glob'. */
57 #define GLOB_NOSPACE 1 /* Ran out of memory. */
58 #define GLOB_ABORTED 2 /* Read error. */
59 #define GLOB_NOMATCH 3 /* No matches found. */
60 #define GLOB_NOSYS 4 /* Not implemented. */
62 /* Structure describing a globbing run. */
64 size_t gl_pathc; /* Count of paths matched by the pattern. */
65 char **gl_pathv; /* List of matched pathnames. */
66 size_t gl_offs; /* Slots to reserve in `gl_pathv'. */
67 int gl_flags; /* Set to FLAGS, maybe | GLOB_MAGCHAR. */
69 /* If the GLOB_ALTDIRFUNC flag is set, the following functions
70 are used instead of the normal file access functions. */
71 void (*gl_closedir)(void *);
72 struct dirent *(*gl_readdir)(void *);
73 void *(*gl_opendir)(const char *);
74 int (*gl_lstat)(const char *, struct stat *);
75 int (*gl_stat)(const char *, struct stat *);
78 #define NAMLEN(_d) NLENGTH(_d)
80 #if (defined POSIX || defined WINDOWS32) && !defined __GNU_LIBRARY__
81 /* Posix does not require that the d_ino field be present, and some
82 systems do not provide it. */
83 #define REAL_DIR_ENTRY(dp) 1
85 #define REAL_DIR_ENTRY(dp) (dp->d_ino != 0)
90 #define __set_errno(val) errno = (val)
94 #include <rpm/rpmfileutil.h>
95 #include <rpm/rpmurl.h>
99 /* Outcomment the following line for production quality code. */
100 /* #define NDEBUG 1 */
102 #define GLOB_INTERFACE_VERSION 1
104 static void globfree(glob_t * pglob);
105 static inline const char *next_brace_sub(const char *begin);
106 static int glob_in_dir(const char *pattern, const char *directory,
108 int (*errfunc) (const char *, int),
110 static int prefix_array(const char *prefix, char **array, size_t n);
111 static int collated_compare(const void *, const void *);
114 static void * mempcpy(void *dest, const void *src, size_t n)
116 return (char *) memcpy(dest, src, n) + n;
120 /* Find the end of the sub-pattern in a brace expression. We define
121 this as an inline function if the compiler permits. */
122 static inline const char *next_brace_sub(const char *begin)
124 unsigned int depth = 0;
125 const char *cp = begin;
127 while (*cp != '\0') {
128 if ((*cp == '}' && depth-- == 0) || (*cp == ',' && depth == 0))
135 return *cp != '\0' ? cp : NULL;
138 static int __glob_pattern_p(const char *pattern, int quote);
140 /* Do glob searching for PATTERN, placing results in PGLOB.
141 The bits defined above may be set in FLAGS.
142 If a directory cannot be opened or read and ERRFUNC is not nil,
143 it is called with the pathname that caused the error, and the
144 `errno' value from the failing call; if it returns non-zero
145 `glob' returns GLOB_ABORTED; if it returns zero, the error is ignored.
146 If memory cannot be allocated for PGLOB, GLOB_NOSPACE is returned.
147 Otherwise, `glob' returns zero. */
149 glob(const char *pattern, int flags,
150 int (*errfunc)(const char *, int), glob_t * pglob)
152 const char *filename;
158 if (pattern == NULL || pglob == NULL || (flags & ~__GLOB_FLAGS) != 0) {
163 if (flags & GLOB_BRACE) {
164 const char *begin = strchr(pattern, '{');
166 /* Allocate working buffer large enough for our work. Note that
167 we have at least an opening and closing brace. */
174 char onealt[strlen(pattern) - 1];
176 /* We know the prefix for all sub-patterns. */
177 alt_start = mempcpy(onealt, pattern, begin - pattern);
179 /* Find the first sub-pattern and at the same time find the
180 rest after the closing brace. */
181 next = next_brace_sub(begin + 1);
183 /* It is an illegal expression. */
184 return glob(pattern, flags & ~GLOB_BRACE, errfunc, pglob);
187 /* Now find the end of the whole brace expression. */
189 while (*rest != '}') {
190 rest = next_brace_sub(rest + 1);
192 /* It is an illegal expression. */
193 return glob(pattern, flags & ~GLOB_BRACE, errfunc,
197 /* Please note that we now can be sure the brace expression
199 rest_len = strlen(++rest) + 1;
201 /* We have a brace expression. BEGIN points to the opening {,
202 NEXT points past the terminator of the first element, and END
203 points past the final }. We will accumulate result names from
204 recursive runs for each brace alternative in the buffer using
207 if (!(flags & GLOB_APPEND)) {
208 /* This call is to set a new vector, so clear out the
209 vector so we can append to it. */
211 pglob->gl_pathv = NULL;
213 firstc = pglob->gl_pathc;
219 /* Construct the new glob expression. */
220 mempcpy(mempcpy(alt_start, p, next - p), rest, rest_len);
222 result = glob(onealt,
223 ((flags & ~(GLOB_NOCHECK | GLOB_NOMAGIC))
224 | GLOB_APPEND), errfunc, pglob);
226 /* If we got an error, return it. */
227 if (result && result != GLOB_NOMATCH) {
228 if (!(flags & GLOB_APPEND))
234 /* We saw the last entry. */
238 next = next_brace_sub(p);
239 assert(next != NULL);
242 if (pglob->gl_pathc != firstc)
243 /* We found some entries. */
245 else if (!(flags & (GLOB_NOCHECK | GLOB_NOMAGIC)))
250 /* Find the filename. */
251 filename = strrchr(pattern, '/');
252 if (filename == NULL) {
253 /* This can mean two things: a simple name or "~name". The latter
254 case is nothing but a notation for a directory. */
255 if ((flags & (GLOB_TILDE | GLOB_TILDE_CHECK)) && pattern[0] == '~') {
257 dirlen = strlen(pattern);
259 /* Set FILENAME to NULL as a special flag. This is ugly but
260 other solutions would require much more code. We test for
261 this special case below. */
268 } else if (filename == pattern) {
275 dirlen = filename - pattern;
276 newp = (char *) alloca(dirlen + 1);
277 *((char *) mempcpy(newp, pattern, dirlen)) = '\0';
281 if (filename[0] == '\0' && dirlen > 1) {
282 /* "pattern/". Expand "pattern", appending slashes. */
283 int val = glob(dirname, flags | GLOB_MARK, errfunc, pglob);
285 pglob->gl_flags = ((pglob->gl_flags & ~GLOB_MARK)
286 | (flags & GLOB_MARK));
291 if (!(flags & GLOB_APPEND)) {
293 pglob->gl_pathv = NULL;
296 oldcount = pglob->gl_pathc;
298 if ((flags & (GLOB_TILDE | GLOB_TILDE_CHECK)) && dirname[0] == '~') {
299 if (dirname[1] == '\0' || dirname[1] == '/') {
300 /* Look up home directory. */
301 const char *home_dir = getenv("HOME");
302 if (home_dir == NULL || home_dir[0] == '\0') {
305 success = (name = getlogin()) != NULL;
310 home_dir = p->pw_dir;
313 if (home_dir == NULL || home_dir[0] == '\0') {
314 if (flags & GLOB_TILDE_CHECK)
317 home_dir = "~"; /* No luck. */
319 /* Now construct the full directory. */
320 if (dirname[1] == '\0')
324 size_t home_len = strlen(home_dir);
325 newp = (char *) alloca(home_len + dirlen);
326 mempcpy(mempcpy(newp, home_dir, home_len),
327 &dirname[1], dirlen);
332 char *end_name = strchr(dirname, '/');
333 const char *user_name;
334 const char *home_dir;
336 if (end_name == NULL)
337 user_name = dirname + 1;
340 newp = (char *) alloca(end_name - dirname + 1);
341 *((char *) mempcpy(newp, dirname + 1, end_name - dirname))
346 /* Look up specific user's home directory. */
349 p = getpwnam(user_name);
351 home_dir = p->pw_dir;
355 /* If we found a home directory use this. */
356 if (home_dir != NULL) {
358 size_t home_len = strlen(home_dir);
359 size_t rest_len = end_name == NULL ? 0 : strlen(end_name);
360 newp = (char *) alloca(home_len + rest_len + 1);
361 *((char *) mempcpy(mempcpy(newp, home_dir, home_len),
362 end_name, rest_len)) = '\0';
364 } else if (flags & GLOB_TILDE_CHECK)
365 /* We have to regard it as an error if we cannot find the
371 /* Now test whether we looked for "~" or "~NAME". In this case we
372 can give the answer now. */
373 if (filename == NULL) {
376 /* Return the directory if we don't check for error or if it exists. */
377 if ((flags & GLOB_NOCHECK)
378 || (((flags & GLOB_ALTDIRFUNC)
379 ? (*pglob->gl_stat) (dirname, &st)
380 : stat(dirname, &st)) == 0 && S_ISDIR(st.st_mode))) {
382 = (char **) xrealloc(pglob->gl_pathv,
384 ((flags & GLOB_DOOFFS) ?
385 pglob->gl_offs : 0) +
386 1 + 1) * sizeof(char *));
388 if (flags & GLOB_DOOFFS)
389 while (pglob->gl_pathc < pglob->gl_offs)
390 pglob->gl_pathv[pglob->gl_pathc++] = NULL;
392 pglob->gl_pathv[pglob->gl_pathc] = xstrdup(dirname);
393 if (pglob->gl_pathv[pglob->gl_pathc] == NULL) {
394 free(pglob->gl_pathv);
397 pglob->gl_pathv[++pglob->gl_pathc] = NULL;
398 pglob->gl_flags = flags;
407 if (__glob_pattern_p(dirname, !(flags & GLOB_NOESCAPE))) {
408 /* The directory name contains metacharacters, so we
409 have to glob for the directory, and then glob for
410 the pattern in each directory found. */
414 if ((flags & GLOB_ALTDIRFUNC) != 0) {
415 /* Use the alternative access functions also in the recursive
417 dirs.gl_opendir = pglob->gl_opendir;
418 dirs.gl_readdir = pglob->gl_readdir;
419 dirs.gl_closedir = pglob->gl_closedir;
420 dirs.gl_stat = pglob->gl_stat;
421 dirs.gl_lstat = pglob->gl_lstat;
424 status = glob(dirname,
425 ((flags & (GLOB_ERR | GLOB_NOCHECK | GLOB_NOESCAPE
427 | GLOB_NOSORT | GLOB_ONLYDIR), errfunc, &dirs);
431 /* We have successfully globbed the preceding directory name.
432 For each name we found, call glob_in_dir on it and FILENAME,
433 appending the results to PGLOB. */
434 for (i = 0; i < dirs.gl_pathc; ++i) {
435 int old_pathc = pglob->gl_pathc;
436 status = glob_in_dir(filename, dirs.gl_pathv[i],
437 ((flags | GLOB_APPEND)
438 & ~(GLOB_NOCHECK | GLOB_ERR)),
440 if (status == GLOB_NOMATCH)
441 /* No matches in this directory. Try the next. */
450 /* Stick the directory on the front of each name. */
451 if (prefix_array(dirs.gl_pathv[i],
452 &pglob->gl_pathv[old_pathc],
453 pglob->gl_pathc - old_pathc)) {
460 flags |= GLOB_MAGCHAR;
462 /* We have ignored the GLOB_NOCHECK flag in the `glob_in_dir' calls.
463 But if we have not found any matching entry and thie GLOB_NOCHECK
464 flag was set we must return the list consisting of the disrectory
465 names followed by the filename. */
466 if (pglob->gl_pathc == oldcount) {
468 if (flags & GLOB_NOCHECK) {
469 size_t filename_len = strlen(filename) + 1;
473 /* This is an pessimistic guess about the size. */
475 = (char **) xrealloc(pglob->gl_pathv,
477 ((flags & GLOB_DOOFFS) ?
478 pglob->gl_offs : 0) +
482 if (flags & GLOB_DOOFFS)
483 while (pglob->gl_pathc < pglob->gl_offs)
484 pglob->gl_pathv[pglob->gl_pathc++] = NULL;
486 for (i = 0; i < dirs.gl_pathc; ++i) {
487 const char *dir = dirs.gl_pathv[i];
488 size_t dir_len = strlen(dir);
490 /* First check whether this really is a directory. */
491 if (((flags & GLOB_ALTDIRFUNC)
492 ? (*pglob->gl_stat) (dir, &st) : stat(dir,
494 || !S_ISDIR(st.st_mode))
495 /* No directory, ignore this entry. */
498 pglob->gl_pathv[pglob->gl_pathc] = xmalloc(dir_len + 1
503 (pglob->gl_pathv[pglob->gl_pathc], dir,
504 dir_len), "/", 1), filename, filename_len);
508 pglob->gl_pathv[pglob->gl_pathc] = NULL;
509 pglob->gl_flags = flags;
511 /* Now we know how large the gl_pathv vector must be. */
512 new_pathv = (char **) xrealloc(pglob->gl_pathv,
513 ((pglob->gl_pathc + 1)
515 pglob->gl_pathv = new_pathv;
522 status = glob_in_dir(filename, dirname, flags, errfunc, pglob);
527 /* Stick the directory on the front of each name. */
528 int ignore = oldcount;
530 if ((flags & GLOB_DOOFFS) && ignore < pglob->gl_offs)
531 ignore = pglob->gl_offs;
533 if (prefix_array(dirname,
534 &pglob->gl_pathv[ignore],
535 pglob->gl_pathc - ignore)) {
542 if (flags & GLOB_MARK) {
543 /* Append slashes to directory names. */
546 for (i = oldcount; i < pglob->gl_pathc; ++i)
547 if (((flags & GLOB_ALTDIRFUNC)
548 ? (*pglob->gl_stat) (pglob->gl_pathv[i], &st)
549 : stat(pglob->gl_pathv[i], &st)) == 0
550 && S_ISDIR(st.st_mode)) {
551 size_t len = strlen(pglob->gl_pathv[i]) + 2;
552 char *new = xrealloc(pglob->gl_pathv[i], len);
553 strcpy(&new[len - 2], "/");
554 pglob->gl_pathv[i] = new;
558 if (!(flags & GLOB_NOSORT)) {
559 /* Sort the vector. */
560 int non_sort = oldcount;
562 if ((flags & GLOB_DOOFFS) && pglob->gl_offs > oldcount)
563 non_sort = pglob->gl_offs;
565 qsort(& pglob->gl_pathv[non_sort],
566 pglob->gl_pathc - non_sort,
567 sizeof(char *), collated_compare);
574 /* Free storage allocated in PGLOB by a previous `glob' call. */
575 static void globfree(glob_t * pglob)
577 if (pglob->gl_pathv != NULL) {
579 for (i = 0; i < pglob->gl_pathc; ++i)
580 if (pglob->gl_pathv[i] != NULL)
581 free(pglob->gl_pathv[i]);
582 free(pglob->gl_pathv);
587 /* Do a collated comparison of A and B. */
588 static int collated_compare(const void * a, const void * b)
590 const char *const s1 = *(const char *const *const) a;
591 const char *const s2 = *(const char *const *const) b;
599 return strcoll(s1, s2);
603 /* Prepend DIRNAME to each of N members of ARRAY, replacing ARRAY's
604 elements in place. Return nonzero if out of memory, zero if successful.
605 A slash is inserted between DIRNAME and each elt of ARRAY,
606 unless DIRNAME is just "/". Each old element of ARRAY is freed. */
607 static int prefix_array(const char *dirname, char **array, size_t n)
610 size_t dirlen = strlen(dirname);
612 if (dirlen == 1 && dirname[0] == '/')
613 /* DIRNAME is just "/", so normal prepending would get us "//foo".
614 We want "/foo" instead, so don't prepend any chars from DIRNAME. */
617 for (i = 0; i < n; ++i) {
618 size_t eltlen = strlen(array[i]) + 1;
619 char *new = (char *) xmalloc(dirlen + 1 + eltlen);
621 char *endp = (char *) mempcpy(new, dirname, dirlen);
623 mempcpy(endp, array[i], eltlen);
632 /* Return nonzero if PATTERN contains any metacharacters.
633 Metacharacters can be quoted with backslashes if QUOTE is nonzero. */
634 static int __glob_pattern_p(const char *pattern, int quote)
636 register const char *p;
637 int openBrackets = 0;
639 for (p = pattern; *p != '\0'; ++p)
646 if (quote && p[1] != '\0')
663 /* Like `glob', but PATTERN is a final pathname component,
664 and matches are searched for in DIRECTORY.
665 The GLOB_NOSORT bit in FLAGS is ignored. No sorting is ever done.
666 The GLOB_APPEND flag is assumed to be set (always appends). */
668 glob_in_dir(const char *pattern, const char *directory, int flags,
669 int (*errfunc)(const char *, int), glob_t * pglob)
671 void * stream = NULL;
674 struct globlink *next;
677 struct globlink *names = NULL;
682 meta = __glob_pattern_p(pattern, !(flags & GLOB_NOESCAPE));
684 if (flags & (GLOB_NOCHECK | GLOB_NOMAGIC))
685 /* We need not do any tests. The PATTERN contains no meta
686 characters and we must not return an error therefore the
687 result will always contain exactly one name. */
688 flags |= GLOB_NOCHECK;
690 /* Since we use the normal file functions we can also use stat()
691 to verify the file is there. */
693 size_t patlen = strlen(pattern);
694 size_t dirlen = strlen(directory);
695 char *fullname = (char *) alloca(dirlen + 1 + patlen + 1);
697 mempcpy(mempcpy(mempcpy(fullname, directory, dirlen),
698 "/", 1), pattern, patlen + 1);
699 if (((flags & GLOB_ALTDIRFUNC)
700 ? (*pglob->gl_stat) (fullname, &st)
701 : stat(fullname, &st)) == 0)
702 /* We found this file to be existing. Now tell the rest
703 of the function to copy this name into the result. */
704 flags |= GLOB_NOCHECK;
709 if (pattern[0] == '\0') {
710 /* This is a special case for matching directories like in
712 names = (struct globlink *) alloca(sizeof(struct globlink));
713 names->name = (char *) xmalloc(1);
714 names->name[0] = '\0';
719 stream = ((flags & GLOB_ALTDIRFUNC)
720 ? (*pglob->gl_opendir) (directory)
721 : opendir(directory));
722 if (stream == NULL) {
724 && ((errfunc != NULL && (*errfunc) (directory, errno))
725 || (flags & GLOB_ERR)))
730 int fnm_flags = ((!(flags & GLOB_PERIOD) ? FNM_PERIOD : 0) |
731 ((flags & GLOB_NOESCAPE) ? FNM_NOESCAPE : 0));
733 flags |= GLOB_MAGCHAR;
738 struct dirent *d = ((flags & GLOB_ALTDIRFUNC)
739 ? (*pglob->gl_readdir) (stream)
740 : readdir((DIR *) stream));
743 if (!REAL_DIR_ENTRY(d))
746 #ifdef HAVE_STRUCT_DIRENT_D_TYPE
747 /* If we shall match only directories use the information
748 provided by the dirent call if possible. */
749 if ((flags & GLOB_ONLYDIR)
750 && d->d_type != DT_UNKNOWN && d->d_type != DT_DIR)
756 if (fnmatch(pattern, name, fnm_flags) == 0) {
757 struct globlink *new = (struct globlink *)
758 alloca(sizeof(struct globlink));
760 new->name = (char *) xmalloc(len + 1);
761 *((char *) mempcpy(new->name, name, len))
772 if (nfound == 0 && (flags & GLOB_NOCHECK)) {
773 size_t len = strlen(pattern);
775 names = (struct globlink *) alloca(sizeof(struct globlink));
777 names->name = (char *) xmalloc(len + 1);
778 *((char *) mempcpy(names->name, pattern, len)) = '\0';
783 = (char **) xrealloc(pglob->gl_pathv,
785 ((flags & GLOB_DOOFFS) ? pglob->
786 gl_offs : 0) + nfound +
787 1) * sizeof(char *));
789 if (flags & GLOB_DOOFFS)
790 while (pglob->gl_pathc < pglob->gl_offs)
791 pglob->gl_pathv[pglob->gl_pathc++] = NULL;
793 for (; names != NULL; names = names->next)
794 pglob->gl_pathv[pglob->gl_pathc++] = names->name;
795 pglob->gl_pathv[pglob->gl_pathc] = NULL;
797 pglob->gl_flags = flags;
801 if (stream != NULL) {
802 if (flags & GLOB_ALTDIRFUNC)
803 (*pglob->gl_closedir) (stream);
805 closedir((DIR *) stream);
809 return nfound == 0 ? GLOB_NOMATCH : 0;
812 /* librpmio exported interfaces */
814 int rpmGlob(const char * patterns, int * argcPtr, ARGV_t * argvPtr)
817 const char ** av = NULL;
820 char * globRoot = NULL;
821 const char *home = getenv("HOME");
824 char * old_collate = NULL;
825 char * old_ctype = NULL;
832 gflags |= GLOB_BRACE;
834 if (home != NULL && strlen(home) > 0)
835 gflags |= GLOB_TILDE;
837 /* Can't use argvSplit() here, it doesn't handle whitespace etc escapes */
838 rc = poptParseArgvString(patterns, &ac, &av);
843 t = setlocale(LC_COLLATE, NULL);
845 old_collate = xstrdup(t);
846 t = setlocale(LC_CTYPE, NULL);
848 old_ctype = xstrdup(t);
849 (void) setlocale(LC_COLLATE, "C");
850 (void) setlocale(LC_CTYPE, "C");
854 for (j = 0; j < ac; j++) {
857 int ut = urlPath(av[j], &path);
858 int local = (ut == URL_IS_PATH) || (ut == URL_IS_UNKNOWN);
859 size_t plen = strlen(path);
861 int dir_only = (plen > 0 && path[plen-1] == '/');
864 if (!local || (!rpmIsGlob(av[j], 0) && strchr(path, '~') == NULL)) {
865 argvAdd(&argv, av[j]);
870 flags |= GLOB_ONLYDIR;
875 rc = glob(av[j], flags, NULL, &gl);
879 /* XXX Prepend the URL leader for globs that have stripped it off */
881 for (i = 0; i < gl.gl_pathc; i++) {
882 if ((nb = strlen(&(gl.gl_pathv[i][0]))) > maxb)
886 nb = ((ut == URL_IS_PATH) ? (path - av[j]) : 0);
889 globURL = globRoot = xmalloc(maxb);
894 strncpy(globRoot, av[j], nb);
907 for (i = 0; i < gl.gl_pathc; i++) {
908 const char * globFile = &(gl.gl_pathv[i][0]);
912 if (lstat(gl.gl_pathv[i], &sb) || !S_ISDIR(sb.st_mode))
916 if (globRoot > globURL && globRoot[-1] == '/')
917 while (*globFile == '/') globFile++;
918 strcpy(globRoot, globFile);
919 argvAdd(&argv, globURL);
925 argc = argvCount(argv);
939 (void) setlocale(LC_COLLATE, old_collate);
943 (void) setlocale(LC_CTYPE, old_ctype);
948 if (rc || argvPtr == NULL) {
954 int rpmIsGlob(const char * pattern, int quote)
956 if (!__glob_pattern_p(pattern, quote)) {
962 begin = strchr(pattern, '{');
966 * Find the first sub-pattern and at the same time find the
967 * rest after the closing brace.
969 next = next_brace_sub(begin + 1);
973 /* Now find the end of the whole brace expression. */
975 while (*rest != '}') {
976 rest = next_brace_sub(rest + 1);
980 /* Now we can be sure that brace expression is well-foermed. */