1 #include <string>
2 #include <string_view>
3 #include <map>
4 #include <set>
5 #include <algorithm>
6 #include <iterator>
7 #include <iostream>
8
9 // This is a slow larval-stage kludge to help massage the generated man
10 // pages. It's used like this:
11 const std::string_view usage = R"(
12 Takes on stdin, whitespace-separated words of the form
13
14 [bits/]stl_foo.h
15 [bits/]std_foo.h
16
17 and writes on stdout the nearest matching standard header name.
18
19 Takes no command-line arguments.
20 )";
21
22 // List of standard headers
23 std::set<std::string_view> std_headers;
24 // Map of partial header filenames to standard headers.
25 std::map<std::string_view, std::string_view> headers;
26
init_map()27 void init_map()
28 {
29 // Enter the glamourous world of data entry!! Maintain these!
30 // Because the map_header function removes common prefixes and suffixes,
31 // a header "bits/st[dl]_foo.h" will automatically map to "foo" if that
32 // is a standard header, so we don't need to list those cases here.
33 headers["atomic_base.h"] = "atomic";
34 headers["atomic_lockfree_defines.h"] = "atomic";
35 headers["atomic_timed_wait.h"] = "atomic";
36 headers["atomic_wait.h"] = "atomic";
37 headers["algorithmfwd.h"] = "algorithm";
38 headers["algo.h"] = "algorithm";
39 headers["algobase.h"] = "algorithm";
40 headers["ranges_algo.h"] = "algorithm";
41 headers["ranges_algobase.h"] = "algorithm";
42 headers["heap.h"] = "algorithm";
43 headers["exception_ptr.h"] = "exception";
44 headers["nested_exception.h"] = "exception";
45 headers["fs_dir.h"] = "filesystem";
46 headers["fs_fwd.h"] = "filesystem";
47 headers["fs_ops.h"] = "filesystem";
48 headers["fs_path.h"] = "filesystem";
49 headers["binders.h"] = "functional";
50 headers["function.h"] = "functional";
51 headers["functional_hash.h"] = "functional";
52 headers["mofunc_impl.h"] = "functional";
53 headers["move_only_function.h"] = "functional";
54 headers["invoke.h"] = "functional";
55 headers["refwrap.h"] = "functional";
56 headers["quoted_string.h"] = "iomanip";
57 headers["ios_base.h"] = "ios";
58 headers["basic_ios.h"] = "ios";
59 headers["basic_ios.tcc"] = "ios";
60 headers["iosfwd.h"] = "iosfwd";
61 headers["iostream.h"] = "iostream";
62 headers["iterator_base_funcs.h"] = "iterator";
63 headers["iterator_base_types.h"] = "iterator";
64 headers["stream_iterator.h"] = "iterator";
65 headers["streambuf_iterator.h"] = "iterator";
66 headers["iterator_concepts.h"] = "iterator";
67 headers["range_access.h"] = "iterator";
68 headers["codecvt.h"] = "locale";
69 headers["c++locale.h"] = "locale";
70 headers["localefwd.h"] = "locale";
71 headers["ctype_base.h"] = "locale";
72 headers["locale_classes.h"] = "locale";
73 headers["locale_classes.tcc"] = "locale";
74 headers["locale_facets.h"] = "locale";
75 headers["locale_facets.tcc"] = "locale";
76 headers["locale_facets_nonio.h"] = "locale";
77 headers["locale_facets_nonio.tcc"] = "locale";
78 headers["locale_conv.h"] = "locale";
79 headers["multimap.h"] = "map";
80 headers["memoryfwd.h"] = "memory";
81 headers["align.h"] = "memory";
82 headers["alloc_traits.h"] = "memory";
83 headers["auto_ptr.h"] = "memory";
84 headers["construct.h"] = "memory";
85 headers["allocator.h"] = "memory";
86 headers["raw_storage_iter.h"] = "memory";
87 headers["tempbuf.h"] = "memory";
88 headers["uninitialized.h"] = "memory";
89 headers["shared_ptr.h"] = "memory";
90 headers["shared_ptr_base.h"] = "memory";
91 headers["shared_ptr_atomic.h"] = "memory";
92 headers["unique_ptr.h"] = "memory";
93 headers["ranges_uninitialized.h"] = "memory";
94 headers["ptr_traits.h"] = "memory";
95 headers["uses_allocator.h"] = "memory";
96 headers["uses_allocator_args.h"] = "memory";
97 headers["unique_lock.h"] = "mutex";
98 headers["uniform_int_dist.h"] = "random";
99 headers["ranges_base.h"] = "ranges";
100 headers["ranges_util.h"] = "ranges";
101 headers["ranges_cmp.h"] = "functional";
102 headers["regex_automaton.h"] = "regex";
103 headers["regex_automaton.tcc"] = "regex";
104 headers["regex_compiler.h"] = "regex";
105 headers["regex_compiler.tcc"] = "regex";
106 headers["regex_constants.h"] = "regex";
107 headers["regex_error.h"] = "regex";
108 headers["regex_executor.h"] = "regex";
109 headers["regex_executor.tcc"] = "regex";
110 headers["regex_scanner.h"] = "regex";
111 headers["regex_scanner.tcc"] = "regex";
112 headers["semaphore_base.h"] = "semaphore";
113 headers["multiset.h"] = "set";
114 headers["node_handle.h"] = "set";
115 headers["functexcept.h"] = "stdexcept";
116 headers["char_traits.h"] = "string";
117 headers["stringfwd.h"] = "string";
118 headers["postypes.h"] = "string";
119 headers["basic_string.h"] = "string";
120 headers["basic_string.tcc"] = "string";
121 headers["cow_string.h"] = "string";
122 headers["string_view.tcc"] = "string_view";
123 headers["this_thread_sleep.h"] = "thread";
124 headers["tree.h"] = "map";
125 headers["pair.h"] = "utility";
126 headers["relops.h"] = "utility";
127 headers["gslice.h"] = "valarray";
128 headers["gslice_array.h"] = "valarray";
129 headers["indirect_array.h"] = "valarray";
130 headers["mask_array.h"] = "valarray";
131 headers["slice_array.h"] = "valarray";
132 headers["valarray_after.h"] = "valarray";
133 headers["valarray_before.h"] = "valarray";
134 headers["valarray_array.h"] = "valarray";
135 headers["valarray_array.tcc"] = "valarray";
136 headers["valarray_meta.h"] = "valarray";
137 headers["bvector.h"] = "vector";
138
139 //headers["concurrence.h"] who knows
140 //headers["atomicity.h"] who knows
141
142 headers["abs.h"] = "cstdlib";
143 headers["specfun.h"] = "cmath";
144
145 // This list is complete as of the October 2021 working draft.
146 std_headers = {
147 "algorithm", "any", "array", "atomic",
148 "barrier", "bit", "bitset",
149 "charconv", "chrono", "codecvt", "compare", "complex",
150 "concepts", "condition_variable", "coroutine",
151 "deque",
152 "exception", "execution",
153 "filesystem", "format", "forward_list", "fstream",
154 "functional", "future",
155 "initializer_list", "iomanip", "ios", "iosfwd",
156 "iostream", "istream", "iterator",
157 "latch", "limits", "list", "locale",
158 "map", "memory", "memory_resource", "mutex",
159 "new", "numbers", "numeric",
160 "optional", "ostream",
161 "queue",
162 "random", "ranges", "ratio", "regex",
163 "scoped_allocator", "semaphore", "set", "shared_mutex",
164 "source_location", "span", "spanstream", "sstream",
165 "stack", "stacktrace", "stdexcept", "stop_token",
166 "streambuf", "string", "string_view", "strstream",
167 "syncstream", "system_error",
168 "thread", "tuple", "typeindex", "typeinfo", "type_traits",
169 "unordered_map", "unordered_set", "utility",
170 "valarray", "variant", "vector", "version",
171
172 "cassert", "cctype", "cerrno", "cfenv", "cfloat",
173 "cinttypes", "climits", "clocale", "cmath", "csetjmp",
174 "csignal", "cstdarg", "cstddef", "cstdint", "cstdio",
175 "cstdlib", "cstring", "ctime", "cuchar", "cwchar",
176 "cwctype",
177
178 "assert.h", "ctype.h", "errno.h", "fenv.h", "float.h",
179 "inttypes.h", "limits.h", "locale.h", "math.h", "setjmp.h",
180 "signal.h", "stdarg.h", "stddef.h", "stdint.h", "stdio.h",
181 "stdlib.h", "string.h", "time.h", "uchar.h", "wchar.h",
182 "wctype.h",
183 };
184
185 // In case we missed any:
186 for (const auto& h : headers)
187 std_headers.insert(h.second);
188 }
189
190
map_header(std::string_view header)191 std::string_view map_header (std::string_view header)
192 {
193 // if it doesn't contain a "." then it's already a std header
194 if (!header.contains('.'))
195 {
196 // make sure it's in the set:
197 std_headers.insert(header);
198 return header;
199 }
200
201 for (std::string_view prefix : {"bits/", "stl_", "std_"})
202 if (header.starts_with(prefix))
203 header.remove_prefix(prefix.size());
204
205 if (auto it = headers.find(header); it != headers.end())
206 return it->second;
207
208 for (std::string_view ext : {".h", ".tcc"})
209 if (header.ends_with(ext))
210 {
211 header.remove_suffix(ext.size());
212 break;
213 }
214
215 if (auto it = std_headers.find(header); it != std_headers.end())
216 return *it;
217
218 return {};
219 }
220
map_header_or_complain(std::string header)221 std::string map_header_or_complain (std::string header)
222 {
223 // For <experimental/xxx.h> and <tr1/xxx.h> try to map <xxx.h>
224 // then add the directory back to it.
225 if (header.contains('.'))
226 for (std::string_view dir : {"experimental/", "tr1/"})
227 if (header.starts_with(dir))
228 {
229 auto h = map_header(header.substr(dir.size()));
230 if (!h.empty())
231 return std::string(dir) + std::string(h);
232 return std::string(header);
233 }
234
235 if (auto mapped = map_header(header); !mapped.empty())
236 return std::string(mapped);
237
238 std::cerr << "Could not map <" << header << "> to a standard header\n";
239 return std::string(header);
240 }
241
242
main(int argc,char ** argv)243 int main (int argc, char** argv)
244 {
245 if (argc > 1)
246 {
247 std::cerr << "Usage: " << argv[0] << '\n' << usage;
248 return 1;
249 }
250
251 init_map();
252
253 std::transform(std::istream_iterator<std::string>(std::cin), {},
254 std::ostream_iterator<std::string>(std::cout),
255 map_header_or_complain);
256 }
257