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 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 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 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 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