Line data Source code
1 : // Copyright (c) 2011-2022 Made to Order Software Corp. All Rights Reserved
2 : //
3 : // https://snapwebsites.org/project/snapdev
4 : // contact@m2osw.com
5 : //
6 : // This program is free software; you can redistribute it and/or modify
7 : // it under the terms of the GNU General Public License as published by
8 : // the Free Software Foundation; either version 2 of the License, or
9 : // (at your option) any later version.
10 : //
11 : // This program is distributed in the hope that it will be useful,
12 : // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 : // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 : // GNU General Public License for more details.
15 : //
16 : // You should have received a copy of the GNU General Public License along
17 : // with this program; if not, write to the Free Software Foundation, Inc.,
18 : // 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19 : #pragma once
20 :
21 : // self
22 : //
23 : #include "snapdev/reverse_cstring.h"
24 :
25 :
26 : // C++ lib
27 : //
28 : #include <string>
29 :
30 :
31 :
32 : namespace snapdev
33 : {
34 : namespace pathinfo
35 : {
36 :
37 :
38 : /** \brief Retrieve the basename of a path.
39 : *
40 : * This function retrieves the basename of a path. You can also remove the
41 : * suffix (often called a file extension) and a prefix.
42 : *
43 : * \code
44 : * // the following returns true
45 : * snap::string_pathinfo_basename(
46 : * "/usr/share/snapwebsites/in.basename.txt"
47 : * , ".txt"
48 : * , "in.") == "basename"
49 : * \endcode
50 : *
51 : * \tparam StringT The type of string to parse.
52 : * \param[in] path The path from which basename gets retrieved.
53 : * \param[in] suffix If the path ends with that suffix, remove it.
54 : * \param[in] prefix If the path starts with that prefix, remove it.
55 : *
56 : * \return The basename of \p path.
57 : */
58 : template<class StringT>
59 : StringT basename(StringT const & path
60 : , typename std::decay<StringT>::type const & suffix = ""
61 : , typename std::decay<StringT>::type const & prefix = "")
62 : {
63 : // ignore path if present
64 : //
65 : typename StringT::size_type pos(path.find_last_of('/'));
66 : if(pos == StringT::npos)
67 : {
68 : // if no '/' in string, the entire name is a basename
69 : //
70 : pos = 0;
71 : }
72 : else
73 : {
74 : ++pos; // skip the actual '/'
75 : }
76 :
77 : // ignore prefix if present
78 : //
79 : if(prefix.length() <= path.length() - pos
80 : && path.compare(pos, prefix.length(), prefix) == 0)
81 : {
82 : pos += prefix.length();
83 : }
84 :
85 : // if the path ends with suffix, then return the path without it
86 : //
87 : if(suffix.length() <= path.length() - pos
88 : && path.compare(path.length() - suffix.length(), suffix.length(), suffix) == 0)
89 : {
90 : return path.substr(pos, path.length() - pos - suffix.length());
91 : }
92 :
93 : // no suffix in this case
94 : //
95 : return path.substr(pos);
96 : }
97 :
98 :
99 : /** \brief Replace the suffix with another.
100 : *
101 : * This function checks whether a file ends with a given suffix. If so then
102 : * the existing suffix gets removed. Then it happens the new suffix.
103 : *
104 : * The function is not checking whether a suffix starts with a period.
105 : * It can include any other character.
106 : *
107 : * \code
108 : * // the following expressions return true
109 : * snap::string_pathinfo_replace_suffix(
110 : * "/usr/share/snapwebsites/replace.cpp"
111 : * , ".cpp"
112 : * , ".h") == "/usr/share/snapwebsites/replace.h"
113 : *
114 : * snap::string_pathinfo_replace_suffix(
115 : * "/usr/share/snapwebsites/replace"
116 : * , ".cpp"
117 : * , ".h") == "/usr/share/snapwebsites/replace.h"
118 : * \endcode
119 : *
120 : * \note
121 : * By default, the \p new_suffix parameter is set to the empty string.
122 : * This means the function can be used to trim the string from
123 : * \p old_suffix.
124 : *
125 : * \todo
126 : * Add a function which supports an array of \p old_suffix.
127 : *
128 : * \tparam StringT The type of string to parse.
129 : * \param[in] path The path from which to replace a suffix.
130 : * \param[in] old_suffix If the path ends with that suffix, remove it.
131 : * \param[in] new_suffix Append this suffix.
132 : * \param[in] no_change_on_missing If old_suffix is missing, do not change
133 : * the \t path.
134 : *
135 : * \return \p path with its suffix replaced as defined above.
136 : */
137 : template<class StringT>
138 28 : StringT replace_suffix(
139 : StringT const & path
140 : , typename std::decay<StringT>::type const & old_suffix
141 : , typename std::decay<StringT>::type const & new_suffix = ""
142 : , bool no_change_on_missing = false)
143 : {
144 : // TODO: with C++20 we could use: path.ends_with(old_suffix)
145 : //
146 56 : if(path.length() >= old_suffix.length()
147 28 : && path.c_str() + path.length() - old_suffix.length() == old_suffix)
148 : {
149 12 : return path.substr(0, path.length() - old_suffix.length()) + new_suffix;
150 : }
151 :
152 16 : if(no_change_on_missing)
153 : {
154 4 : return path;
155 : }
156 :
157 12 : return path + new_suffix;
158 : }
159 :
160 :
161 : /** \brief Retrieve the directory name of a path.
162 : *
163 : * This function retrieves the directory name of a path. The returned path
164 : * is the empty string if the input does not include any '/'.
165 : *
166 : * \code
167 : * // the following returns true
168 : * snap::string_pathinfo_dirname(
169 : * "/usr/share/snapwebsites/in.filename.txt");
170 : * == "/usr/share/snapwebsites";
171 : * \endcode
172 : *
173 : * \param[in] path The path from which basename gets retrieved.
174 : *
175 : * \return The directory name of \p path.
176 : */
177 : template < class StringT >
178 2 : StringT dirname(StringT const & path)
179 : {
180 2 : typename StringT::size_type pos(path.find_last_of('/'));
181 2 : if(pos == StringT::npos)
182 : {
183 0 : return StringT();
184 : }
185 2 : else if(pos == 0)
186 : {
187 0 : if(path[0] == '/')
188 : {
189 0 : return StringT("/");
190 : }
191 0 : return StringT(".");
192 : }
193 : else
194 : {
195 2 : return path.substr(0, pos);
196 : }
197 : }
198 :
199 : } // namespace pathinfo
200 : } // namespace snapdev
201 : // vim: ts=4 sw=4 et
|