1 /* pathfinder.h: find one of multiple file names in path list
3 This file is part of Cygwin.
5 This software is a copyrighted work licensed under the terms of the
6 Cygwin license. Please consult the file "CYGWIN_LICENSE" for
13 /* Search a list of directory names for first occurrence of a file,
14 which's file name matches one out of a list of file names. */
18 typedef vstrlist searchdirlist
;
19 typedef vstrlist basenamelist
;
23 pathfinder (pathfinder
const &);
24 pathfinder
& operator = (pathfinder
const &);
26 basenamelist basenames_
;
27 size_t basenames_maxlen_
;
29 /* Add to searchdirs_ with extra buffer for any basename we may search for.
30 This is an optimization for the loops in check_path_access method. */
31 searchdirlist searchdirs_
;
36 /* We need the basenames to search for first, to allow for optimized
37 memory allocation of each searchpath + longest basename combination.
38 The incoming list of basenames is emptied (ownership take over). */
39 pathfinder (allocator_interface
& a
, basenamelist
& basenames
)
41 , basenames_maxlen_ ()
44 basenames_
.swap(basenames
);
46 for (basenamelist::buffer_iterator
basename (basenames_
.begin ());
47 basename
!= basenames_
.end ();
50 if (basenames_maxlen_
< basename
->bufferlength ())
51 basenames_maxlen_
= basename
->bufferlength ();
55 void add_searchdir (const char *dir
, int dirlen
)
58 dirlen
= strlen (dir
);
63 searchdirs_
.appendv (dir
, dirlen
, "/", 1 + basenames_maxlen_
, NULL
);
66 void add_searchpath (const char *path
)
70 const char *next
= strchr (path
, ':');
71 add_searchdir (path
, next
? next
- path
: -1);
72 path
= next
? next
+ 1 : next
;
76 void add_envsearchpath (const char *envpath
)
78 add_searchpath (getenv (envpath
));
82 /* pathfinder::criterion_interface
83 Overload this test method when you need separate dir and basename. */
84 struct criterion_interface
86 virtual char const * name () const { return NULL
; }
88 virtual bool test (searchdirlist::iterator dir
,
89 basenamelist::iterator name
) const = 0;
93 /* pathfinder::simple_criterion_interface
94 Overload this test method when you need a single filename. */
95 class simple_criterion_interface
96 : public criterion_interface
98 virtual bool test (searchdirlist::iterator dir
,
99 basenamelist::iterator name
) const
101 /* Complete the filename path to search for within dir,
102 We have allocated enough memory above. */
103 searchdirlist::buffer_iterator
dirbuf (dir
);
104 memcpy (dirbuf
->buffer () + dirbuf
->stringlength (),
105 name
->string (), name
->stringlength () + 1);
106 bool ret
= test (dirbuf
->string ());
107 /* reset original dir */
108 dirbuf
->buffer ()[dirbuf
->stringlength ()] = '\0';
113 virtual bool test (const char * filename
) const = 0;
117 /* pathfinder::path_conv_criterion_interface
118 Overload this test method when you need a path_conv. */
119 class path_conv_criterion_interface
120 : public simple_criterion_interface
126 /* simple_criterion_interface */
127 virtual bool test (const char * filename
) const
129 pc_
.check (filename
, opt_
);
134 path_conv_criterion_interface (unsigned opt
= PC_SYM_FOLLOW
)
140 path_conv_criterion_interface (path_conv
& ret
, unsigned opt
= PC_SYM_FOLLOW
)
146 virtual bool test (path_conv
& pc
) const = 0;
150 /* pathfinder::exists_and_not_dir
151 Test if path_conv argument does exist and is not a directory. */
152 struct exists_and_not_dir
153 : public path_conv_criterion_interface
155 virtual char const * name () const { return "exists and not dir"; }
157 exists_and_not_dir (path_conv
& pc
, unsigned opt
= PC_SYM_FOLLOW
)
158 : path_conv_criterion_interface (pc
, opt
)
161 /* path_conv_criterion_interface */
162 virtual bool test (path_conv
& pc
) const
164 if (pc
.exists () && !pc
.isdir ())
173 /* Find the single dir + basename that matches criterion.
175 Calls criterion.test method for each registered dir + basename
176 until returning true:
177 Returns true with found_dir + found_basename set.
178 If criterion.test method never returns true:
179 Returns false, not modifying found_dir nor found_basename. */
180 bool find (criterion_interface
const & criterion
,
181 searchdirlist::member
const ** found_dir
= NULL
,
182 basenamelist::member
const ** found_basename
= NULL
)
184 char const * critname
= criterion
.name ();
185 for (searchdirlist::iterator
dir(searchdirs_
.begin ());
186 dir
!= searchdirs_
.end ();
188 for (basenamelist::iterator name
= basenames_
.begin ();
189 name
!= basenames_
.end ();
191 if (criterion
.test (dir
, name
))
193 debug_printf ("(%s), take %s%s", critname
,
194 dir
->string(), name
->string ());
196 *found_dir
= dir
.operator -> ();
198 *found_basename
= name
.operator -> ();
202 debug_printf ("not (%s), skip %s%s", critname
,
203 dir
->string(), name
->string ());
208 #endif /* __cplusplus */