1 /*
2  * Copyright (C) 2007-2015 Tim Mayberry <mojofunk@gmail.com>
3  * Copyright (C) 2008-2009 David Robillard <d@drobilla.net>
4  * Copyright (C) 2008-2015 Paul Davis <paul@linuxaudiosystems.com>
5  * Copyright (C) 2013-2014 John Emmas <john@creativepost.co.uk>
6  * Copyright (C) 2014-2015 Robin Gareus <robin@gareus.org>
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License along
19  * with this program; if not, write to the Free Software Foundation, Inc.,
20  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21  */
22 
23 #include <string>
24 
25 #include <glib.h>
26 #include <glibmm/miscutils.h>
27 
28 #include "pbd/replace_all.h"
29 #include "pbd/tokenizer.h"
30 #include "pbd/search_path.h"
31 #include "pbd/error.h"
32 
33 using namespace std;
34 
35 namespace PBD {
36 
Searchpath()37 Searchpath::Searchpath ()
38 {
39 
40 }
41 
Searchpath(const string & path)42 Searchpath::Searchpath (const string& path)
43 {
44 	vector<std::string> tmp;
45 
46 	if (tokenize (path, string(G_SEARCHPATH_SEPARATOR_S), std::back_inserter (tmp))) {
47 		add_directories (tmp);
48 	}
49 }
50 
Searchpath(const vector<std::string> & paths)51 Searchpath::Searchpath (const vector<std::string>& paths)
52 {
53 	add_directories (paths);
54 }
55 
56 void
remove_directory(const std::string & directory_path)57 Searchpath::remove_directory (const std::string& directory_path)
58 {
59 	if (directory_path.empty()) {
60 		return;
61 	}
62 
63 	for (vector<std::string>::iterator i = begin(); i != end();) {
64 		if (*i == directory_path) {
65 			i = erase (i);
66 		} else {
67 			++i;
68 		}
69 	}
70 }
71 
72 void
remove_directories(const vector<std::string> & paths)73 Searchpath::remove_directories (const vector<std::string>& paths)
74 {
75 	for(vector<std::string>::const_iterator i = paths.begin(); i != paths.end(); ++i) {
76 		remove_directory (*i);
77 	}
78 }
79 
80 void
add_directory(const std::string & directory_path)81 Searchpath::add_directory (const std::string& directory_path)
82 {
83 	if (directory_path.empty()) {
84 		return;
85 	}
86 	for (vector<std::string>::const_iterator i = begin(); i != end(); ++i) {
87 		if (poor_mans_glob (*i) == poor_mans_glob(directory_path)) {
88 			return;
89 		}
90 	}
91 	push_back(directory_path);
92 }
93 
94 void
add_directories(const vector<std::string> & paths)95 Searchpath::add_directories (const vector<std::string>& paths)
96 {
97 	for(vector<std::string>::const_iterator i = paths.begin(); i != paths.end(); ++i) {
98 		add_directory (*i);
99 	}
100 }
101 
102 const string
to_string() const103 Searchpath::to_string () const
104 {
105 	string path;
106 
107 	for (vector<std::string>::const_iterator i = begin(); i != end(); ++i) {
108 		path += *i;
109 		path += G_SEARCHPATH_SEPARATOR;
110 	}
111 
112 	path = path.substr (0, path.length() - 1); // drop final separator
113 
114 	return path;
115 }
116 
117 Searchpath&
operator +=(const Searchpath & spath)118 Searchpath::operator+= (const Searchpath& spath)
119 {
120 	for (vector<std::string>::const_iterator i = spath.begin(); i != spath.end(); ++i) {
121 		add_directory (*i);
122 	}
123 	return *this;
124 }
125 
126 Searchpath&
operator +=(const std::string & directory_path)127 Searchpath::operator+= (const std::string& directory_path)
128 {
129 	add_directory (directory_path);
130 	return *this;
131 }
132 
133 const Searchpath
operator +(const std::string & directory_path)134 Searchpath::operator+ (const std::string& directory_path)
135 {
136 	return Searchpath (*this) += directory_path;
137 }
138 
139 const Searchpath
operator +(const Searchpath & spath)140 Searchpath::operator+ (const Searchpath& spath)
141 {
142 	return Searchpath (*this) += spath;
143 }
144 
145 Searchpath&
operator -=(const Searchpath & spath)146 Searchpath::operator-= (const Searchpath& spath)
147 {
148 	remove_directories (spath);
149 	return *this;
150 }
151 
152 Searchpath&
operator -=(const std::string & directory_path)153 Searchpath::operator-= (const std::string& directory_path)
154 {
155 	remove_directory (directory_path);
156 	return *this;
157 }
158 
159 
160 Searchpath&
add_subdirectory_to_paths(const string & subdir)161 Searchpath::add_subdirectory_to_paths (const string& subdir)
162 {
163 	for (vector<std::string>::iterator i = begin(); i != end(); ++i) {
164 		// should these new paths just be added to the end of
165 		// the search path rather than replace?
166 		*i = Glib::build_filename (*i, subdir);
167 	}
168 
169 	return *this;
170 }
171 
172 bool
contains(const string & path) const173 Searchpath::contains (const string& path) const
174 {
175 	std::vector<std::string>::const_iterator i = find(begin(), end(), path);
176 
177 	if (i == end()) {
178 		return false;
179 	}
180 	return true;
181 }
182 
183 /* This is not part of the Searchpath object, but is closely related to the
184  * whole idea, and we put it here for convenience.
185  */
186 
187 void
export_search_path(const string & base_dir,const char * varname,const char * dir)188 export_search_path (const string& base_dir, const char* varname, const char* dir)
189 {
190 	string path;
191 	const char * cstr = g_getenv (varname);
192 
193 	if (cstr) {
194 		path = cstr;
195 		path += G_SEARCHPATH_SEPARATOR;
196 	} else {
197 		path = "";
198 	}
199 	path += base_dir;
200 	path += dir;
201 
202 	g_setenv (varname, path.c_str(), 1);
203 }
204 
205 } // namespace PBD
206