1 /** 2 * Copyright: Copyright (c) 2012 Jacob Carlborg. All rights reserved. 3 * Authors: Jacob Carlborg 4 * Version: Initial created: Jun 15, 2012 5 * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0) 6 */ 7 module dstep.translator.IncludeHandler; 8 9 import std.array : Appender; 10 11 import clang.c.Index; 12 import clang.Cursor; 13 import clang.Util; 14 15 import dstep.translator.HeaderIndex; 16 import dstep.translator.Options; 17 import dstep.translator.Output; 18 19 class IncludeHandler 20 { 21 private Options options; 22 private string[string] submodules; 23 private bool[string] includes; 24 private bool[string] imports; 25 private HeaderIndex headerIndex; 26 immutable static string[string] knownIncludes; 27 28 shared static this () 29 { 30 knownIncludes = [ 31 "complex" : "core.stdc.complex", 32 "config" : "core.stdc.config", 33 "ctype" : "core.stdc.ctype", 34 "errno" : "core.stdc.errno", 35 "fenv" : "core.stdc.fenv", 36 "float" : "core.stdc.float", 37 "inttypes" : "core.stdc.inttypes", 38 "limits" : "core.stdc.limits", 39 "locale" : "core.stdc.locale", 40 "math" : "core.stdc.math", 41 "signal" : "core.stdc.signal", 42 "stdarg" : "core.stdc.stdarg", 43 "stddef" : "core.stdc.stddef", 44 "stdint" : "core.stdc.stdint", 45 "_int8_t" : "core.stdc.stdint", 46 "_int16_t" : "core.stdc.stdint", 47 "_int32_t" : "core.stdc.stdint", 48 "_int64_t" : "core.stdc.stdint", 49 "_uint8_t" : "core.stdc.stdint", 50 "_uint16_t" : "core.stdc.stdint", 51 "_uint32_t" : "core.stdc.stdint", 52 "_uint64_t" : "core.stdc.stdint", 53 "stdio" : "core.stdc.stdio", 54 "_stdio" : "core.stdc.stdio", 55 "corecrt_wstdio" : "core.stdc.stdio", 56 "stdlib" : "core.stdc.stdlib", 57 "string" : "core.stdc.string", 58 "tgmath" : "core.stdc.tgmath", 59 "time" : "core.stdc.time", 60 "_time_t" : "core.stdc.time", 61 "corecrt" : "core.stdc.time", 62 "crtdefs" : "core.stdc.time", 63 "wchar" : "core.stdc.wchar_", 64 "wctype" : "core.stdc.wctype", 65 66 "dirent" : "core.sys.posix.dirent", 67 "dlfcn" : "core.sys.posix.dlfcn", 68 "fcntl" : "core.sys.posix.fcntl", 69 "netdb" : "core.sys.posix.netdb", 70 "poll" : "core.sys.posix.poll", 71 "pthread" : "core.sys.posix.pthread", 72 "pwd" : "core.sys.posix.pwd", 73 "sched" : "core.sys.posix.sched", 74 "semaphore" : "core.sys.posix.semaphore", 75 "setjmp" : "core.sys.posix.setjmp", 76 "signal" : "core.sys.posix.signal", 77 "termios" : "core.sys.posix.termios", 78 "ucontext" : "core.sys.posix.ucontext", 79 "unistd" : "core.sys.posix.unistd", 80 "utime" : "core.sys.posix.utime", 81 82 "arpa/inet" : "core.sys.posix.arpa.inet", 83 84 "net/if" : "core.sys.posix.net.if_", 85 86 "netinet/in" : "core.sys.posix.netinet.in_", 87 "netinet/tcp" : "core.sys.posix.netinet.tcp", 88 89 "sys/ipc" : "core.sys.posix.sys.ipc", 90 "sys/mman" : "core.sys.posix.sys.mman", 91 "sys/select" : "core.sys.posix.sys.select", 92 "sys/shm" : "core.sys.posix.sys.shm", 93 "sys/socket" : "core.sys.posix.sys.socket", 94 "sys/stat" : "core.sys.posix.sys.stat", 95 "sys/time" : "core.sys.posix.sys.time", 96 "_time_t" : "core.stdc.time", 97 "sys/types" : "core.sys.posix.sys.types", 98 "sys/_types" : "core.sys.posix.sys.types", 99 "sys/uio" : "core.sys.posix.sys.uio", 100 "sys/un" : "core.sys.posix.sys.un", 101 "sys/utsname" : "core.sys.posix.sys.utsname", 102 "sys/wait" : "core.sys.posix.sys.wait", 103 104 "windows" : "core.sys.windows.windows" 105 ]; 106 } 107 108 this (HeaderIndex headerIndex, Options options) 109 { 110 import std.format; 111 import std.algorithm : filter; 112 113 this.headerIndex = headerIndex; 114 this.options = options; 115 116 if (options.packageName != "") 117 { 118 auto inputFiles = options.inputFiles.filter!( 119 x => x != options.inputFile); 120 121 foreach (file; inputFiles) 122 { 123 auto packageName = options.packageName; 124 auto normalize = options.normalizeModules; 125 submodules[file] = fullModuleName(packageName, file, normalize); 126 } 127 } 128 } 129 130 void addInclude (string include) 131 { 132 import std.path; 133 import std.file; 134 import std.array; 135 136 auto absolute = include.asAbsNormPath; 137 138 if (absolute != options.inputFile && !include.empty) 139 { 140 if (exists(absolute) && isFile(absolute)) 141 includes[absolute] = true; 142 else 143 includes[include] = true; 144 } 145 } 146 147 void addImport (string imp) 148 { 149 imports[imp] = true; 150 } 151 152 void addCompatible () 153 { 154 includes["config.h"] = true; 155 } 156 157 void toImports (Output output) 158 { 159 import std.algorithm : map; 160 import std.array : array; 161 import std.format : format; 162 import std.algorithm.iteration : filter, map; 163 164 Set!string standard, package_, unhandled; 165 166 foreach (entry; includes.byKey) 167 { 168 if (auto i = isKnownInclude(entry)) 169 standard.add(toImport(i)); 170 else if (auto i = isPackageSubmodule(entry)) 171 package_.add(toSubmoduleImport(i)); 172 else 173 unhandled.add(format(`/+ #include "%s" +/`, entry)); 174 } 175 176 auto extra = imports.byKey.map!(e => toImport(e)).array; 177 178 importsBlock(output, standard.keys ~ extra.array); 179 importsBlock(output, package_.keys); 180 181 if (options.keepUntranslatable) 182 importsBlock(output, unhandled.keys); 183 184 output.finalize(); 185 } 186 187 bool resolveDependency(in Cursor cursor) 188 { 189 auto module_ = headerIndex.searchKnownModules(cursor); 190 191 if (module_ !is null) 192 { 193 addImport(module_); 194 return true; 195 } 196 197 return false; 198 } 199 200 private: 201 202 void importsBlock(Output output, string[] imports) 203 { 204 import std.array : empty; 205 import std.algorithm : sort, filter; 206 207 foreach (entry; imports.sort().filter!(e => !e.empty)) 208 output.singleLine(entry); 209 210 if (!output.empty) 211 output.separator(); 212 } 213 214 string toImport (string str) 215 { 216 return "import " ~ str ~ ";"; 217 } 218 219 string toSubmoduleImport (string str) 220 { 221 if (options.publicSubmodules) 222 return "public import " ~ str ~ ";"; 223 else 224 return "import " ~ str ~ ";"; 225 } 226 227 string isKnownInclude (string include) 228 { 229 import std.path : stripExtension, baseName; 230 231 include = stripExtension(baseName(include)); 232 233 if (auto ptr = include in knownIncludes) 234 return *ptr; 235 else 236 return null; 237 } 238 239 string isPackageSubmodule (string include) 240 { 241 if (auto ptr = include in submodules) 242 return *ptr; 243 else 244 return null; 245 } 246 }