diff options
author | Michael Haubenwallner <michael.haubenwallner@ssi-schaefer.com> | 2016-08-31 20:07:06 +0200 |
---|---|---|
committer | Corinna Vinschen <corinna@vinschen.de> | 2016-09-08 13:36:29 +0200 |
commit | 97974e3076f26d4031a95722116eb45bc98b5571 (patch) | |
tree | e68d7303dc0bd0780de866c864df0d23f2050cb0 /winsup/cygwin/pathfinder.h | |
parent | 091a0ac120e2c220a7b2c102e2e23d9b4b543ff6 (diff) | |
download | newlib-97974e3076f26d4031a95722116eb45bc98b5571.zip newlib-97974e3076f26d4031a95722116eb45bc98b5571.tar.gz newlib-97974e3076f26d4031a95722116eb45bc98b5571.tar.bz2 |
dlopen: switch to new pathfinder class
Instead of find_exec, without changing behaviour use new pathfinder
class with new allocator_interface around tmp_pathbuf and new vstrlist
class.
* pathfinder.h (pathfinder): New file.
* vstrlist.h (allocator_interface, allocated_type, vstrlist): New file.
* dlfcn.cc (dlopen): Avoid redundant GetModuleHandleExW with RTLD_NOLOAD
and RTLD_NODELETE. Switch to new pathfinder class, using
(tmp_pathbuf_allocator): New class.
(get_full_path_of_dll): Drop.
Diffstat (limited to 'winsup/cygwin/pathfinder.h')
-rw-r--r-- | winsup/cygwin/pathfinder.h | 208 |
1 files changed, 208 insertions, 0 deletions
diff --git a/winsup/cygwin/pathfinder.h b/winsup/cygwin/pathfinder.h new file mode 100644 index 0000000..bbba168 --- /dev/null +++ b/winsup/cygwin/pathfinder.h @@ -0,0 +1,208 @@ +/* pathfinder.h: find one of multiple file names in path list + +This file is part of Cygwin. + +This software is a copyrighted work licensed under the terms of the +Cygwin license. Please consult the file "CYGWIN_LICENSE" for +details. */ + +#include "vstrlist.h" + +#ifdef __cplusplus + +/* Search a list of directory names for first occurrence of a file, + which's file name matches one out of a list of file names. */ +class pathfinder +{ +public: + typedef vstrlist searchdirlist; + typedef vstrlist basenamelist; + +private: + pathfinder (); + pathfinder (pathfinder const &); + pathfinder & operator = (pathfinder const &); + + basenamelist basenames_; + size_t basenames_maxlen_; + + /* Add to searchdirs_ with extra buffer for any basename we may search for. + This is an optimization for the loops in check_path_access method. */ + searchdirlist searchdirs_; + +public: + ~pathfinder () {} + + /* We need the basenames to search for first, to allow for optimized + memory allocation of each searchpath + longest basename combination. + The incoming list of basenames is emptied (ownership take over). */ + pathfinder (allocator_interface & a, basenamelist & basenames) + : basenames_ (a) + , basenames_maxlen_ () + , searchdirs_(a) + { + basenames_.swap(basenames); + + for (basenamelist::buffer_iterator basename (basenames_.begin ()); + basename != basenames_.end (); + ++ basename) + { + if (basenames_maxlen_ < basename->bufferlength ()) + basenames_maxlen_ = basename->bufferlength (); + } + } + + void add_searchdir (const char *dir, int dirlen) + { + if (dirlen < 0) + dirlen = strlen (dir); + + if (!dirlen) + return; + + searchdirs_.appendv (dir, dirlen, "/", 1 + basenames_maxlen_, NULL); + } + + void add_searchpath (const char *path) + { + while (path && *path) + { + const char *next = strchr (path, ':'); + add_searchdir (path, next ? next - path : -1); + path = next ? next + 1 : next; + } + } + + void add_envsearchpath (const char *envpath) + { + add_searchpath (getenv (envpath)); + } + + + /* pathfinder::criterion_interface + Overload this test method when you need separate dir and basename. */ + struct criterion_interface + { + virtual char const * name () const { return NULL; } + + virtual bool test (searchdirlist::iterator dir, + basenamelist::iterator name) const = 0; + }; + + + /* pathfinder::simple_criterion_interface + Overload this test method when you need a single filename. */ + class simple_criterion_interface + : public criterion_interface + { + virtual bool test (searchdirlist::iterator dir, + basenamelist::iterator name) const + { + /* Complete the filename path to search for within dir, + We have allocated enough memory above. */ + searchdirlist::buffer_iterator dirbuf (dir); + memcpy (dirbuf->buffer () + dirbuf->stringlength (), + name->string (), name->stringlength () + 1); + bool ret = test (dirbuf->string ()); + /* reset original dir */ + dirbuf->buffer ()[dirbuf->stringlength ()] = '\0'; + return ret; + } + + public: + virtual bool test (const char * filename) const = 0; + }; + + + /* pathfinder::path_conv_criterion_interface + Overload this test method when you need a path_conv. */ + class path_conv_criterion_interface + : public simple_criterion_interface + { + path_conv mypc_; + path_conv & pc_; + unsigned opt_; + + /* simple_criterion_interface */ + virtual bool test (const char * filename) const + { + pc_.check (filename, opt_); + return test (pc_); + } + + public: + path_conv_criterion_interface (unsigned opt = PC_SYM_FOLLOW) + : mypc_ () + , pc_ (mypc_) + , opt_ (opt) + {} + + path_conv_criterion_interface (path_conv & ret, unsigned opt = PC_SYM_FOLLOW) + : mypc_ () + , pc_ (ret) + , opt_ (opt) + {} + + virtual bool test (path_conv & pc) const = 0; + }; + + + /* pathfinder::exists_and_not_dir + Test if path_conv argument does exist and is not a directory. */ + struct exists_and_not_dir + : public path_conv_criterion_interface + { + virtual char const * name () const { return "exists and not dir"; } + + exists_and_not_dir (path_conv & pc, unsigned opt = PC_SYM_FOLLOW) + : path_conv_criterion_interface (pc, opt) + {} + + /* path_conv_criterion_interface */ + virtual bool test (path_conv & pc) const + { + if (pc.exists () && !pc.isdir ()) + return true; + + pc.error = ENOENT; + return false; + } + }; + + + /* Find the single dir + basename that matches criterion. + + Calls criterion.test method for each registered dir + basename + until returning true: + Returns true with found_dir + found_basename set. + If criterion.test method never returns true: + Returns false, not modifying found_dir nor found_basename. */ + bool find (criterion_interface const & criterion, + searchdirlist::member const ** found_dir = NULL, + basenamelist::member const ** found_basename = NULL) + { + char const * critname = criterion.name (); + for (basenamelist::iterator name = basenames_.begin (); + name != basenames_.end (); + ++name) + for (searchdirlist::iterator dir(searchdirs_.begin ()); + dir != searchdirs_.end (); + ++dir) + if (criterion.test (dir, name)) + { + debug_printf ("(%s), take %s%s", critname, + dir->string(), name->string ()); + if (found_dir) + *found_dir = dir.operator -> (); + if (found_basename) + *found_basename = name.operator -> (); + return true; + } + else + debug_printf ("not (%s), skip %s%s", critname, + dir->string(), name->string ()); + return false; + } +}; + +#endif /* __cplusplus */ |