Cygwin: (mostly) drop NT4 and Samba < 3.0 support
[newlib-cygwin.git] / winsup / cygwin / local_includes / pathfinder.h
blobc3066044bf6a812f9d9427d07dfcc7b94aeade57
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
7 details. */
9 #include "vstrlist.h"
11 #ifdef __cplusplus
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. */
15 class pathfinder
17 public:
18 typedef vstrlist searchdirlist;
19 typedef vstrlist basenamelist;
21 private:
22 pathfinder ();
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_;
33 public:
34 ~pathfinder () {}
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)
40 : basenames_ (a)
41 , basenames_maxlen_ ()
42 , searchdirs_(a)
44 basenames_.swap(basenames);
46 for (basenamelist::buffer_iterator basename (basenames_.begin ());
47 basename != basenames_.end ();
48 ++ basename)
50 if (basenames_maxlen_ < basename->bufferlength ())
51 basenames_maxlen_ = basename->bufferlength ();
55 void add_searchdir (const char *dir, int dirlen)
57 if (dirlen < 0)
58 dirlen = strlen (dir);
60 if (!dirlen)
61 return;
63 searchdirs_.appendv (dir, dirlen, "/", 1 + basenames_maxlen_, NULL);
66 void add_searchpath (const char *path)
68 while (path && *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';
109 return ret;
112 public:
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
122 path_conv mypc_;
123 path_conv & pc_;
124 unsigned opt_;
126 /* simple_criterion_interface */
127 virtual bool test (const char * filename) const
129 pc_.check (filename, opt_);
130 return test (pc_);
133 public:
134 path_conv_criterion_interface (unsigned opt = PC_SYM_FOLLOW)
135 : mypc_ ()
136 , pc_ (mypc_)
137 , opt_ (opt)
140 path_conv_criterion_interface (path_conv & ret, unsigned opt = PC_SYM_FOLLOW)
141 : mypc_ ()
142 , pc_ (ret)
143 , opt_ (opt)
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 ())
165 return true;
167 pc.error = ENOENT;
168 return false;
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 ();
187 ++dir)
188 for (basenamelist::iterator name = basenames_.begin ();
189 name != basenames_.end ();
190 ++name)
191 if (criterion.test (dir, name))
193 debug_printf ("(%s), take %s%s", critname,
194 dir->string(), name->string ());
195 if (found_dir)
196 *found_dir = dir.operator -> ();
197 if (found_basename)
198 *found_basename = name.operator -> ();
199 return true;
201 else
202 debug_printf ("not (%s), skip %s%s", critname,
203 dir->string(), name->string ());
204 return false;
208 #endif /* __cplusplus */