PageRenderTime 85ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 1ms

/cwxeditor_src/cwx/utils.d

https://bitbucket.org/k4nagatsuki/cwxeditor
D | 1853 lines | 1577 code | 93 blank | 183 comment | 411 complexity | dff8cbeb64fb35a5bab66184bcbac71d MD5 | raw file
Possible License(s): LGPL-2.1

Large files files are truncated, but you can click here to view the full file

  1. module cwx.utils;
  2. public import cwx.perf;
  3. import cwx.sjis;
  4. import std.algorithm;
  5. import std.array;
  6. import std.conv;
  7. import std.uni;
  8. import std.metastrings;
  9. import std.string;
  10. import std.format;
  11. import std.file;
  12. import std.path;
  13. import std.uni;
  14. import std.utf;
  15. import std.base64;
  16. import std.stdio;
  17. import std.ascii;
  18. import std.cstream;
  19. import std.traits;
  20. import std.datetime;
  21. import std.regex;
  22. import std.array;
  23. import std.exception;
  24. import std.traits;
  25. import std.stdint;
  26. import std.stream;
  27. import std.range;
  28. debug {
  29. version (Console) {
  30. private immutable DR = "Debug / Console";
  31. } else {
  32. private immutable DR = "Debug";
  33. }
  34. } else {
  35. @property
  36. private immutable DR = "Release";
  37. }
  38. shared immutable string APP_BUILD = "Build: "
  39. ~ __DATE__[7 .. $]
  40. ~ "-" ~ [
  41. "Jan":"01",
  42. "Feb":"02",
  43. "Mar":"03",
  44. "Apr":"04",
  45. "May":"05",
  46. "Jun":"06",
  47. "Jul":"07",
  48. "Aug":"08",
  49. "Sep":"09",
  50. "Oct":"10",
  51. "Nov":"11",
  52. "Dec":"12"
  53. ][__DATE__[0 .. 3]]
  54. ~ "-" ~ (__DATE__[4 .. 5] == " " ? "0" : __DATE__[4 .. 5]) ~ __DATE__[5 .. 6]
  55. ~ " " ~ __TIME__ ~ " "
  56. ~ DR ~ .newline
  57. ~ "Compiled by " ~ __VENDOR__ ~ " " ~ .text(__VERSION__);
  58. private version (Windows) {
  59. import std.windows.charset;
  60. import std.c.stdio;
  61. extern (Windows) {
  62. import std.c.windows.windows;
  63. struct STARTUPINFO {
  64. DWORD cb;
  65. LPTSTR lpReserved;
  66. LPTSTR lpDesktop;
  67. LPTSTR lpTitle;
  68. DWORD dwX;
  69. DWORD dwY;
  70. DWORD dwXSize;
  71. DWORD dwYSize;
  72. DWORD dwXCountChars;
  73. DWORD dwYCountChars;
  74. DWORD dwFillAttribute;
  75. DWORD dwFlags;
  76. USHORT wShowWindow;
  77. USHORT cbReserved2;
  78. LPBYTE lpReserved2;
  79. HANDLE hStdInput;
  80. HANDLE hStdOutput;
  81. HANDLE hStdError;
  82. }
  83. struct PROCESS_INFORMATION {
  84. HANDLE hProcess;
  85. HANDLE hThread;
  86. DWORD dwProcessId;
  87. DWORD dwThreadId;
  88. }
  89. BOOL SetFileAttributesW(LPCWSTR, DWORD);
  90. BOOL CreateProcessW(LPCWSTR, LPWSTR, SECURITY_ATTRIBUTES*, SECURITY_ATTRIBUTES*,
  91. BOOL, DWORD, LPVOID, LPCWSTR, STARTUPINFO*, PROCESS_INFORMATION*);
  92. alias HRESULT function(HWND, INT, HANDLE, DWORD, LPWSTR) SHGetFolderPathW;
  93. const CSIDL_APPDATA = 0x1A;
  94. const SHGFP_TYPE_CURRENT = 0;
  95. }
  96. } else { mixin(S_TRACE);
  97. import core.sys.posix.unistd;
  98. import core.sys.posix.pwd;
  99. import std.c.string;
  100. }
  101. shared string LATEST_VERSION = "";
  102. string printStackTrace() {
  103. string[] arr = ["Stack Trace --------"];
  104. foreach (ref s; stStack) {
  105. arr ~= .format("%s, %s", s.file, s.line);
  106. }
  107. auto s = arr.join("\n");
  108. fdebugln(s);
  109. stStack = [];
  110. return createDebugln(s);
  111. }
  112. shared string debugLog = "cwxeditor_error.log";
  113. private __gshared BufferedFile debugLogFile = null;
  114. /// FIXME: 2.059??altsep??
  115. version (Windows) {
  116. immutable altDirSeparator = "/";
  117. } else version (Posix) {
  118. immutable altDirSeparator = " ";
  119. } else static assert (0);
  120. immutable curdir = ".";
  121. immutable pardir = "..";
  122. /// ???????????
  123. string debugString(T)(ref T v) { mixin(S_TRACE);
  124. static if (is(T : Throwable)) {
  125. char[] trace;
  126. if (v.info) { mixin(S_TRACE);
  127. foreach (file; v.info) { mixin(S_TRACE);
  128. if (trace.length) { mixin(S_TRACE);
  129. trace ~= " - ".dup;
  130. }
  131. try { mixin(S_TRACE);
  132. for (size_t i = 0; i < file.length; i++) { mixin(S_TRACE);
  133. char c = file[i];
  134. .validate([c]);
  135. trace ~= c;
  136. }
  137. } catch (Exception e) {
  138. /// info?????????????????
  139. /// ???????????????
  140. }
  141. }
  142. }
  143. return .format("[%s] %s, %d: ", v.msg, v.file, v.line) ~ trace.idup;
  144. } else { mixin(S_TRACE);
  145. return .format("%s", v);
  146. }
  147. }
  148. /// ditto
  149. string createDebugln(bool BuildInfo = true, string F = __FILE__, size_t L = __LINE__, T ...)(T vals) { mixin(S_TRACE);
  150. char[] buf = format("%s:%d ", F, L).dup;
  151. foreach (v; vals) { mixin(S_TRACE);
  152. static if (is(typeof(v) : Throwable)) {
  153. buf ~= debugString(v);
  154. } else static if (is(typeof(v) : string)) {
  155. buf ~= v;
  156. } else { mixin(S_TRACE);
  157. buf ~= debugString(v);
  158. }
  159. }
  160. auto d = Clock.currTime();
  161. int year = d.year;
  162. int month = d.month;
  163. int day = d.day;
  164. int hour = d.hour;
  165. int min = d.minute;
  166. int second = d.second;
  167. static if (BuildInfo) {
  168. buf = format("%04d-%02d-%02d %02d:%02d:%02d", year, month, day, hour, min, second) ~ " [" ~ .splitLines!string(APP_BUILD)[0] ~ "]\t" ~ buf;
  169. } else { mixin(S_TRACE);
  170. buf = format("%04d-%02d-%02d %02d:%02d:%02d", year, month, day, hour, min, second) ~ " " ~ buf;
  171. }
  172. return assumeUnique(buf);
  173. }
  174. /// ???????????????
  175. void fdebugln(string F = __FILE__, size_t L = __LINE__, T ...)(T vals) { mixin(S_TRACE);
  176. try { mixin(S_TRACE);
  177. synchronized { mixin(S_TRACE);
  178. string log = createDebugln!(true, F, L)(vals);
  179. version (Console) {
  180. version (Windows) {
  181. printf("%s\n\0".ptr, toMBSz(log));
  182. dout.flush();
  183. } else { mixin(S_TRACE);
  184. writeln(log);
  185. }
  186. }
  187. if (!debugLog.dirName().exists()) { mixin(S_TRACE);
  188. debugLog.dirName().mkdirRecurse();
  189. }
  190. if (!debugLogFile) { mixin(S_TRACE);
  191. debugLogFile = new typeof(debugLogFile)(debugLog, FileMode.Append);
  192. }
  193. debugLogFile.seekEnd(0);
  194. debugLogFile.writeLine(log);
  195. debugLogFile.flush();
  196. }
  197. } catch (Throwable e) {
  198. std.stdio.writeln(__FILE__, " ", __LINE__, " ", e, e.msg);
  199. std.stdio.writeln(F, " ", L, " ");
  200. }
  201. }
  202. shared static ~this () { mixin(S_TRACE);
  203. version (Console) {
  204. debug std.stdio.writeln("Close Debug log file Start");
  205. }
  206. synchronized { mixin(S_TRACE);
  207. if (debugLogFile) debugLogFile.close();
  208. }
  209. version (Console) {
  210. debug std.stdio.writeln("Close Debug log file Exit");
  211. }
  212. }
  213. /// debug???????????? ???????????????
  214. /// ??fdebugln()??????????????
  215. void debugln(string F = __FILE__, size_t L = __LINE__, T ...)(T vals) { mixin(S_TRACE);
  216. debug {
  217. fdebugln!(F, L, T)(vals);
  218. }
  219. }
  220. /// ??????????????????
  221. void cdebugln(string F = __FILE__, size_t L = __LINE__, T ...)(T vals) { mixin(S_TRACE);
  222. version (Console) {
  223. debug {
  224. synchronized { mixin(S_TRACE);
  225. string log = createDebugln!(false, F, L)(vals);
  226. version (Windows) {
  227. printf("%s\n\0".ptr, toMBSz(log));
  228. dout.flush();
  229. } else { mixin(S_TRACE);
  230. writeln(log);
  231. }
  232. }
  233. }
  234. }
  235. }
  236. /// ????????????????
  237. void cwriteln(string s) { mixin(S_TRACE);
  238. version (Console) {
  239. synchronized { mixin(S_TRACE);
  240. version (Windows) {
  241. printf("%s\n\0".ptr, toMBSz(s));
  242. dout.flush();
  243. } else { mixin(S_TRACE);
  244. writeln(s);
  245. }
  246. }
  247. }
  248. }
  249. version (Windows) {
  250. import core.sys.windows.windows;
  251. /// ?????????????
  252. void* dlopen(string lib) { mixin(S_TRACE);
  253. return LoadLibraryW(.toUTFz!(wchar*)(lib));
  254. }
  255. /// ?????????????????
  256. void* dlsym(void* lib, string sym) { mixin(S_TRACE);
  257. if (!lib) return null;
  258. return GetProcAddress(lib, .toStringz(sym));
  259. }
  260. /// ?????????????
  261. void dlclose(ref void* lib) { mixin(S_TRACE);
  262. if (!lib) return;
  263. FreeLibrary(lib);
  264. lib = null;
  265. }
  266. } else version (Posix) {
  267. import core.sys.posix.dlfcn;
  268. /// ?????????????
  269. void* dlopen(string lib) { mixin(S_TRACE);
  270. return core.sys.posix.dlfcn.dlopen(.toStringz(lib), RTLD_NOW);
  271. }
  272. /// ?????????????????
  273. void* dlsym(void* lib, string sym) { mixin(S_TRACE);
  274. if (!lib) return null;
  275. return core.sys.posix.dlfcn.dlsym(lib, .toStringz(sym));
  276. }
  277. /// ?????????????
  278. void dlclose(ref void* lib) { mixin(S_TRACE);
  279. if (!lib) return;
  280. core.sys.posix.dlfcn.dlclose(lib);
  281. lib = null;
  282. }
  283. } else static assert (0);
  284. /// ???????????????????????????????
  285. string appDataDir(string appPath) { mixin(S_TRACE);
  286. version (Windows) {
  287. auto shl = dlopen("shell32.dll");
  288. if (!shl) { mixin(S_TRACE);
  289. return appPath.dirName();
  290. }
  291. scope (exit) dlclose(shl);
  292. auto getFolderPath = cast(SHGetFolderPathW) dlsym(shl, "SHGetFolderPathW");
  293. if (!getFolderPath) { mixin(S_TRACE);
  294. return appPath.dirName();
  295. }
  296. wchar[MAX_PATH] appDataBuf;
  297. auto gfr = getFolderPath(null, CSIDL_APPDATA, null, SHGFP_TYPE_CURRENT, appDataBuf.ptr);
  298. if (0 != gfr) { mixin(S_TRACE);
  299. return appPath.dirName();
  300. }
  301. auto p = to!string(appDataBuf[0 .. appDataBuf.indexOf('\0')]);
  302. return assumeUnique(p);
  303. } else { mixin(S_TRACE);
  304. return to!string(getpwuid(getuid()).pw_dir);
  305. }
  306. }
  307. static const B_IMG = "binaryimage://";
  308. bool isBinImg(string path) { mixin(S_TRACE);
  309. return path.length >= B_IMG.length && path[0u .. B_IMG.length] == B_IMG;
  310. }
  311. ubyte[] strToBImg(string bimg) { mixin(S_TRACE);
  312. return Base64.decode(bimg[B_IMG.length .. $]);
  313. }
  314. string bImgToStr(in ubyte[] bimg) { mixin(S_TRACE);
  315. auto r = B_IMG ~ Base64.encode(bimg);
  316. return assumeUnique(r);
  317. }
  318. /// Enum???????????????????????
  319. @safe
  320. pure
  321. string enumToString(E)(E e) {
  322. mixin("final switch (e) {"
  323. ~ enumToStringImpl!(E, 0)
  324. ~ "}");
  325. } unittest { mixin(S_TRACE);
  326. debug mixin(UTPerf);
  327. enum En {
  328. Abc, Def
  329. }
  330. assert (enumToString(En.Abc) == "abc");
  331. assert (enumToString(En.Def) == "def");
  332. }
  333. private template enumToStringImpl(E, size_t Index) {
  334. static if (EnumMembers!E.length <= Index) {
  335. immutable enumToStringImpl = "";
  336. } else {
  337. immutable enumToStringImpl = "case E." ~ .text(EnumMembers!E[Index])
  338. ~ ": return `" ~ .capLower(.text(EnumMembers!E[Index])) ~ "`;"
  339. ~ enumToStringImpl!(E, Index + 1);
  340. }
  341. }
  342. /// ?????????Enum????????Enum???????
  343. @safe
  344. pure
  345. E stringToEnum(E)(string name) {
  346. mixin("switch (name) {"
  347. ~ stringToEnumImpl!(E, 0)
  348. ~ "default: return E.init;"
  349. ~ "}");
  350. } unittest { mixin(S_TRACE);
  351. debug mixin(UTPerf);
  352. enum En {
  353. Abc, Def
  354. }
  355. assert (stringToEnum!En("abc") == En.Abc);
  356. assert (stringToEnum!En("def") == En.Def);
  357. }
  358. private template stringToEnumImpl(E, size_t Index) {
  359. static if (EnumMembers!E.length <= Index) {
  360. immutable stringToEnumImpl = "";
  361. } else {
  362. immutable stringToEnumImpl = "case `" ~ .capLower(.text(EnumMembers!E[Index])) ~ "`:"
  363. ~ "return E." ~ .text(EnumMembers!E[Index]) ~ ";"
  364. ~ stringToEnumImpl!(E, Index + 1);
  365. }
  366. }
  367. /// enum?????????????switch???????
  368. template EnumToStringSwitch2(E, string EName, string Prefix) {
  369. immutable EnumToStringSwitch2 = "final switch (id) {\n"
  370. ~ EnumToStringCase!(E, EName, Prefix, 0)
  371. ~ "}";
  372. }
  373. /// ditto
  374. template EnumToStringSwitch(E, string Prefix) {
  375. immutable EnumToStringSwitch = EnumToStringSwitch2!(E, E.stringof, Prefix);
  376. }
  377. /// switch??enum???????????????????????
  378. template EnumToStringMethod2(E, string EName, string MethodName, string Prefix) {
  379. immutable EnumToStringMethod2 = "const string " ~ MethodName ~ "(" ~ EName ~ " id) {\n"
  380. ~ "\tfinal switch (id) {\n"
  381. ~ EnumToStringCase!(E, EName, Prefix, 0)
  382. ~ "\t}\n"
  383. ~ "}";
  384. }
  385. /// ditto
  386. template EnumToStringMethod(E, string MethodName, string Prefix) {
  387. immutable EnumToStringMethod = EnumToStringMethod2!(E, E.stringof, MethodName, Prefix);
  388. }
  389. private template EnumToStringCase(E, string EName, string Prefix, size_t Index) {
  390. private import std.traits;
  391. private import std.conv;
  392. private immutable Case = "\tcase " ~ EName ~ "." ~ to!string(EnumMembers!E[Index]) ~ ": return " ~ Prefix ~ .upperToCap(std.conv.text(EnumMembers!E[Index])) ~ ";\n";
  393. static if (Index + 1 < EnumMembers!E.length) {
  394. immutable EnumToStringCase = Case ~ EnumToStringCase!(E, EName, Prefix, Index + 1);
  395. } else {
  396. immutable EnumToStringCase = Case;
  397. }
  398. }
  399. /// ?????????????????????????????????????
  400. string upperToCap(string s) {
  401. if (!s.length) return s;
  402. bool isCap = true;
  403. foreach (c; s) {
  404. if (std.ascii.isLower(c)) {
  405. isCap = false;
  406. break;
  407. }
  408. }
  409. if (!isCap) return s;
  410. bool ul = true;
  411. char[] buf;
  412. foreach (i, c; s) {
  413. if (ul) {
  414. buf ~= c;
  415. ul = false;
  416. } else if ('_' == c) {
  417. ul = true;
  418. } else {
  419. buf ~= std.ascii.toLower(c);
  420. }
  421. }
  422. return .assumeUnique(buf);
  423. } unittest { mixin(S_TRACE);
  424. assert (upperToCap("UPPER_TO_CAP") == "UpperToCap");
  425. assert (upperToCap("UpperToCap") == "UpperToCap");
  426. }
  427. /// s???1??????????
  428. string capLower(string s) {
  429. if (!s.length) return s;
  430. dstring ds = to!dstring(s);
  431. return to!string([std.uni.toLower(ds[0])] ~ ds[1 .. $]);
  432. }
  433. /// s???1??????????
  434. string capUpper(string s) { mixin(S_TRACE);
  435. if (!s.length) return s;
  436. dstring ds = to!dstring(s);
  437. return to!string([std.uni.toUpper(ds[0])] ~ ds[1 .. $]);
  438. }
  439. /// ???????std.string.format()?
  440. string tryFormat(T ...)(string s, T vals) { mixin(S_TRACE);
  441. try { mixin(S_TRACE);
  442. auto a = appender!string();
  443. formattedWrite(a, s, vals);
  444. return a.data;
  445. } catch (Exception e) {
  446. debugln(s);
  447. debugln(e);
  448. return s;
  449. }
  450. }
  451. /// ????????????????????????
  452. /// *?????????????????????????
  453. /// \????????????????
  454. class Wildcard {
  455. /// s?????????index????
  456. /// ????????-1????
  457. int find(string s) { mixin(S_TRACE);
  458. if (!s.length) return -1;
  459. size_t len;
  460. auto ds = toUTF32(s);
  461. int i = find(ds, false, len);
  462. if (i == -1) return -1;
  463. return toUTF8(ds[0 .. i]).length;
  464. }
  465. /// s??????????true????
  466. bool match(string s) { mixin(S_TRACE);
  467. if (!s.length) { mixin(S_TRACE);
  468. return 0 == _left.length;
  469. }
  470. size_t len;
  471. auto ds = toUTF32(s);
  472. int i = find(ds, false, len);
  473. if (i == -1) return false;
  474. return 0 == i && ds.length == len;
  475. }
  476. /// s??????????to????????
  477. string replace(string s, string to) { mixin(S_TRACE);
  478. if (!s.length) return s;
  479. auto ds = toUTF32(s);
  480. auto dto = toUTF32(to);
  481. dchar[] r;
  482. size_t len;
  483. while (true) { mixin(S_TRACE);
  484. if (!ds.length) break;
  485. int i = find(ds, false, len);
  486. if (i == -1) { mixin(S_TRACE);
  487. r ~= ds;
  488. break;
  489. }
  490. r ~= ds[0 .. i] ~ dto;
  491. ds = ds[i + len .. $];
  492. }
  493. return toUTF8(r);
  494. }
  495. /// s???????????????????
  496. size_t count(string s) { mixin(S_TRACE);
  497. if (!s.length) return 0;
  498. auto ds = toUTF32(s);
  499. size_t r = 0;
  500. size_t len;
  501. while (true) { mixin(S_TRACE);
  502. if (!ds.length) break;
  503. int i = find(ds, false, len);
  504. if (i == -1) { mixin(S_TRACE);
  505. break;
  506. }
  507. r++;
  508. ds = ds[i + len .. $];
  509. }
  510. return r;
  511. }
  512. private enum Pattern {
  513. CHAR, QUESTION
  514. }
  515. private static struct WChar {
  516. Pattern pattern;
  517. dchar chr;
  518. bool ignoreCase;
  519. bool match(dchar c) { mixin(S_TRACE);
  520. switch (pattern) {
  521. case Pattern.CHAR: { mixin(S_TRACE);
  522. if (ignoreCase) { mixin(S_TRACE);
  523. return std.ascii.toLower(chr) == std.ascii.toLower(c);
  524. } else { mixin(S_TRACE);
  525. return chr == c;
  526. }
  527. }
  528. case Pattern.QUESTION: { mixin(S_TRACE);
  529. return true;
  530. }
  531. default: assert (0);
  532. }
  533. }
  534. }
  535. private WChar[] _left;
  536. private Wildcard _right;
  537. private bool _ignoreCase;
  538. private int findw(dstring s) { mixin(S_TRACE);
  539. if (s.length < _left.length) return -1;
  540. for (int i = 0; i <= s.length - _left.length; i++) { mixin(S_TRACE);
  541. int j;
  542. for (j = 0; j < _left.length && _left[j].match(s[i + j]); j++) {}
  543. if (j == _left.length) return i;
  544. }
  545. return -1;
  546. }
  547. private int rfindw(dstring s) { mixin(S_TRACE);
  548. if (s.length < _left.length) return -1;
  549. for (int i = s.length - _left.length; i >= 0; i--) { mixin(S_TRACE);
  550. int j;
  551. for (j = 0; j < _left.length && _left[j].match(s[i + j]); j++) {}
  552. if (j == _left.length) return i;
  553. }
  554. return -1;
  555. }
  556. private int find(ref dstring s, bool next, out size_t len) { mixin(S_TRACE);
  557. auto sbase = s;
  558. while (true) { mixin(S_TRACE);
  559. int i = next ? rfindw(s) : findw(s);
  560. if (i == -1) return -1;
  561. if (_right) { mixin(S_TRACE);
  562. auto refVal = sbase[i + _left.length .. $];
  563. int j = _right.find(refVal, true, len);
  564. if (j == -1) { mixin(S_TRACE);
  565. if (next) { mixin(S_TRACE);
  566. s = s[0 .. $ - 1];
  567. continue;
  568. }
  569. return -1;
  570. }
  571. len += _left.length + j;
  572. return i;
  573. } else { mixin(S_TRACE);
  574. len = _left.length;
  575. return i;
  576. }
  577. }
  578. }
  579. public static Wildcard opCall(string sub, bool ignoreCase = false) {
  580. auto wild = new Wildcard;
  581. wild._ignoreCase = ignoreCase;
  582. bool onbs = false;
  583. foreach (i, dchar c; sub) { mixin(S_TRACE);
  584. switch (c) {
  585. case '?': { mixin(S_TRACE);
  586. if (!onbs) { mixin(S_TRACE);
  587. wild._left ~= WChar(Pattern.QUESTION, '\0', ignoreCase);
  588. onbs = false;
  589. break;
  590. }
  591. } goto default;
  592. case '*': { mixin(S_TRACE);
  593. if (!onbs) { mixin(S_TRACE);
  594. while (i < sub.length && sub[i] == '*')
  595. i++;
  596. wild._right = Wildcard(sub[i .. $], ignoreCase);
  597. return wild;
  598. }
  599. } goto default;
  600. case '\\': { mixin(S_TRACE);
  601. if (onbs) wild._left ~= WChar(Pattern.CHAR, c, ignoreCase);
  602. onbs = !onbs;
  603. } break;
  604. default: { mixin(S_TRACE);
  605. wild._left ~= WChar(Pattern.CHAR, c, ignoreCase);
  606. onbs = false;
  607. }
  608. }
  609. }
  610. if (onbs) wild._left ~= WChar(Pattern.CHAR, '\\', ignoreCase);
  611. return wild;
  612. }
  613. } unittest { mixin(S_TRACE);
  614. debug mixin(UTPerf);
  615. assert (Wildcard("test").find("test") == 0);
  616. assert (Wildcard("test").find("atest") == 1);
  617. assert (Wildcard("te?t").find("test") == 0);
  618. assert (Wildcard("t*t").find("abctest") == 3);
  619. assert (Wildcard("test*").find("test") == 0);
  620. assert (Wildcard("test\\*").find("atest*") == 1);
  621. assert (Wildcard("*test").find("abcdtest") == 0);
  622. assert (Wildcard("te\\?st").find("abcdte?st") == 4);
  623. assert (Wildcard("te\\\\st").find("abcdte\\st") == 4);
  624. assert (Wildcard("t*st").find("testst") == 0);
  625. assert (Wildcard("te\\st").find("te\\st") == -1);
  626. assert (Wildcard("te?t", true).find("tEst") == 0);
  627. assert (Wildcard("t*t", true).find("abcTEST") == 3);
  628. assert (Wildcard("test*", true).find("teST") == 0);
  629. assert (Wildcard("test").match("test"));
  630. assert (!Wildcard("test").match("atest"));
  631. assert (Wildcard("te?t").match("test"));
  632. assert (!Wildcard("t*t").match("abctest"));
  633. assert (Wildcard("test*").match("test"));
  634. assert (!Wildcard("test\\*").match("atest*"));
  635. assert (Wildcard("*test").match("abcdtest"));
  636. assert (!Wildcard("te\\?st").match("abcdte?st"));
  637. assert (!Wildcard("te\\\\st").match("abcdte\\st"));
  638. assert (Wildcard("t*st").match("testst"));
  639. assert (!Wildcard("te\\st").match("te\\st"));
  640. assert (Wildcard("te?t", true).match("tEst"));
  641. assert (!Wildcard("t*t", true).match("abcTEST"));
  642. assert (Wildcard("test*", true).match("teST"));
  643. assert (Wildcard("*").count("test") == 1);
  644. assert (Wildcard("te?t").count("testtestest") == 2);
  645. assert (Wildcard("t*s").replace("test", "A") == "At");
  646. assert (Wildcard("???t").replace("testtestest", "BB") == "BBBBest");
  647. }
  648. /// ???????????????
  649. alias std.file.read readBinary;
  650. /// ????MD5????????????
  651. string md5Digest(in void[] data) { mixin(S_TRACE);
  652. static if (__VERSION__ >= 2061) {
  653. import std.digest.md;
  654. return toHexString(md5Of(data)).idup;
  655. } else { mixin(S_TRACE);
  656. import std.md5;
  657. return getDigestString([data]);
  658. }
  659. }
  660. /// ?????MD5????????????
  661. string fileToMD5Digest(string file) { mixin(S_TRACE);
  662. if (.exists(file)) { mixin(S_TRACE);
  663. try { mixin(S_TRACE);
  664. return md5Digest(readBinary(file));
  665. } catch (FileException e) {
  666. // ??????????????????
  667. debugln(e);
  668. }
  669. }
  670. return "";
  671. }
  672. /// ?????????????
  673. string nabs(string path) { mixin(S_TRACE);
  674. return buildNormalizedPath(absolutePath(path));
  675. }
  676. /// ??????????????????????
  677. string abs2rel(string p1, string p2) { mixin(S_TRACE);
  678. auto rel = relativePath(nabs(p1), nabs(p2));
  679. return rel.buildNormalizedPath();
  680. }
  681. /// ?/?????????startsWith?
  682. bool istartsWith(in char[] a, in char[] b) { mixin(S_TRACE);
  683. if (a.length < b.length) return false;
  684. auto da = a.to!dstring();
  685. auto db = b.to!dstring();
  686. if (da.length < db.length) return false;
  687. return icmp(da[0 .. db.length], db) == 0;
  688. }
  689. /// ?/?????????endsWith?
  690. bool iendsWith(in char[] a, in char[] b) { mixin(S_TRACE);
  691. return a.length >= b.length && icmp(a[$ - b.length .. $], b) == 0;
  692. }
  693. /// path?list????????true????
  694. bool containsPath(in string[] list, string path) { mixin(S_TRACE);
  695. foreach (l; list) { mixin(S_TRACE);
  696. if (cglobMatch(path, l)) return true;
  697. }
  698. return false;
  699. } unittest { mixin(S_TRACE);
  700. debug mixin(UTPerf);
  701. assert (containsPath(["*.txt"], "test.txt"));
  702. assert (containsPath([".*"], ".svn"));
  703. }
  704. /// ???????????startsWith?
  705. bool fnstartsWith(in char[] a, in char[] b) { mixin(S_TRACE);
  706. static if (0 == filenameCharCmp('A', 'a')) {
  707. return istartsWith(a, b);
  708. } else { mixin(S_TRACE);
  709. return startsWith(a, b);
  710. }
  711. }
  712. /// ???????????endsWith?
  713. bool fnendsWith(string a, string b) { mixin(S_TRACE);
  714. static if (0 == filenameCharCmp('A', 'a')) {
  715. return iendsWith(a, b);
  716. } else { mixin(S_TRACE);
  717. return endsWith(a, b);
  718. }
  719. }
  720. /// ?????encode???
  721. string encodePath(string path) { mixin(S_TRACE);
  722. return isBinImg(path) ? path : replace(path, dirSeparator, "/");
  723. }
  724. /// ?????decode???
  725. string decodePath(string path) { mixin(S_TRACE);
  726. return isBinImg(path) ? path : replace(path, "/", dirSeparator);
  727. }
  728. /// ??????????????????
  729. /// ?????????????????????
  730. string lastRet(string text) { mixin(S_TRACE);
  731. if (!text.length) return "";
  732. bool ret = false;
  733. size_t i = text.length;
  734. foreach_reverse (j, char t; text) { mixin(S_TRACE);
  735. if (t == '\n') { mixin(S_TRACE);
  736. i = j;
  737. ret = true;
  738. } else { mixin(S_TRACE);
  739. break;
  740. }
  741. }
  742. if (ret) { mixin(S_TRACE);
  743. text = text[0u .. i + 1u];
  744. } else { mixin(S_TRACE);
  745. text ~= '\n';
  746. }
  747. return text;
  748. } unittest { mixin(S_TRACE);
  749. debug mixin(UTPerf);
  750. assert (lastRet("test\n\n\n") == "test\n");
  751. assert (lastRet("test") == "test\n");
  752. assert (lastRet("t\n\nes\nt\n\n") == "t\n\nes\nt\n");
  753. assert (lastRet("test\n") == "test\n");
  754. }
  755. /// arr?in-place?????????
  756. T[] sort(alias Cmp, T)(T[] arr) { mixin(S_TRACE);
  757. auto dlg = (in T a, in T b) {return Cmp(a, b) < 0;};
  758. return sortDlg!(T, typeof(dlg))(arr, dlg);
  759. }
  760. /// ditto
  761. T[] sortDlg(T, Dlg)(T[] arr, Dlg lmin) { mixin(S_TRACE);
  762. return std.algorithm.sort!(lmin)(arr).array();
  763. } unittest { mixin(S_TRACE);
  764. debug mixin(UTPerf);
  765. assert (sortDlg!(int)([8, 1, 4, 6, 5, 3, 2, 9, 7, 0], (in int a, in int b) {return a < b;})
  766. == [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]);
  767. int[] arr = [5, 2, 3, 4, 6, 7, 9, 1, 0, 8];
  768. sortDlg!(int)(arr, (in int a, in int b) {return a > b;});
  769. assert (arr == [9, 8, 7, 6, 5, 4, 3, 2, 1, 0]);
  770. assert (sortDlg!(string)(["dd", "Bbb", "Cc", "aa"], (in string a, in string b) {return icmp(a, b) < 0;})
  771. == ["aa", "Bbb", "Cc", "dd"]);
  772. }
  773. /// ds??c?????????????????????????????-1????
  774. int qsearch(T)(in T[] ds, T c) { mixin(S_TRACE);
  775. if (ds.length == 1) return ds[0] == c ? 0 : -1;
  776. int i = ds.length / 2;
  777. T c2 = ds[i];
  778. if (c < c2) { mixin(S_TRACE);
  779. if (i == 0) return -1;
  780. return qsearch!(T)(ds[0 .. i], c);
  781. } else if (c > c2) { mixin(S_TRACE);
  782. if (i + 1 == ds.length) return -1;
  783. int i2 = qsearch!(T)(ds[i + 1 .. $], c);
  784. if (i2 == -1) return -1;
  785. return i + i2 + 1;
  786. } else { mixin(S_TRACE);
  787. return i;
  788. }
  789. } unittest { mixin(S_TRACE);
  790. debug mixin(UTPerf);
  791. assert (qsearch([1, 2, 4, 8, 16, 32, 64, 128], 0) == -1);
  792. assert (qsearch([1, 2, 4, 8, 16, 32, 64, 128], 1) == 0);
  793. assert (qsearch([1, 2, 4, 8, 16, 32, 64, 128], 2) == 1);
  794. assert (qsearch([1, 2, 4, 8, 16, 32, 64, 128], 3) == -1);
  795. assert (qsearch([1, 2, 4, 8, 16, 32, 64, 128], 4) == 2);
  796. assert (qsearch([1, 2, 4, 8, 16, 32, 64, 128], 8) == 3);
  797. assert (qsearch([1, 2, 4, 8, 16, 32, 64, 128], 16) == 4);
  798. assert (qsearch([1, 2, 4, 8, 16, 32, 64, 128], 32) == 5);
  799. assert (qsearch([1, 2, 4, 8, 16, 32, 64, 128], 64) == 6);
  800. assert (qsearch([1, 2, 4, 8, 16, 32, 64, 128], 127) == -1);
  801. assert (qsearch([1, 2, 4, 8, 16, 32, 64, 128], 128) == 7);
  802. assert (qsearch([1, 2, 4, 8, 16, 32, 64, 128], 129) == -1);
  803. assert (qsearch([1, 2, 4, 8, 16, 32, 64, 128, 256], 0) == -1);
  804. assert (qsearch([1, 2, 4, 8, 16, 32, 64, 128, 256], 1) == 0);
  805. assert (qsearch([1, 2, 4, 8, 16, 32, 64, 128, 256], 2) == 1);
  806. assert (qsearch([1, 2, 4, 8, 16, 32, 64, 128, 256], 3) == -1);
  807. assert (qsearch([1, 2, 4, 8, 16, 32, 64, 128, 256], 255) == -1);
  808. assert (qsearch([1, 2, 4, 8, 16, 32, 64, 128, 256], 256) == 8);
  809. assert (qsearch([1, 2, 4, 8, 16, 32, 64, 128, 256], 257) == -1);
  810. }
  811. /// ?????????????true?
  812. template isVArray(T) {
  813. const bool isVArray = !is (T : string) && !is (T : wstring) && !is (T : dstring)
  814. && (isDynamicArray!(T) || isStaticArray!(T));
  815. }
  816. /// base?use()?true?????????????
  817. /// base = xxxx????use(base)?false????xxxx (2)?
  818. /// ???use("xxxx (2)")?false????xxxx (3)……???????
  819. /// ???????????????????
  820. /// base????????+1???
  821. /// Params:
  822. /// base = ???????
  823. /// use = ????????????????
  824. /// space = false???????????????????
  825. /// Returns: ??????
  826. string createNewName(string base, bool delegate(string) use, bool space = true) { mixin(S_TRACE);
  827. if (use(base)) return base;
  828. char[] digit;
  829. int digitL = 0;
  830. int digitR = -1;
  831. foreach_reverse (i, c; base) { mixin(S_TRACE);
  832. if (isDigit(c)) { mixin(S_TRACE);
  833. digit.insertInPlace(0, c);
  834. if (digitR == -1) { mixin(S_TRACE);
  835. digitR = i + 1;
  836. }
  837. } else { mixin(S_TRACE);
  838. if (digitR != -1) { mixin(S_TRACE);
  839. digitL = i + 1;
  840. break;
  841. }
  842. }
  843. }
  844. string left, right;
  845. long i = 2;
  846. if (digit.length) { mixin(S_TRACE);
  847. assert (digitR != -1);
  848. left = base[0..digitL];
  849. right = base[digitR..$];
  850. i = to!long(digit);
  851. } else { mixin(S_TRACE);
  852. left = base ~ (space ? " (" : "(");
  853. right = ")";
  854. }
  855. try {
  856. while (true) { mixin(S_TRACE);
  857. auto s = left ~ to!(string)(i) ~ right;
  858. if (use(s)) return s;
  859. if (i + 1 < i) break; // overflow
  860. i++;
  861. }
  862. } catch (Exception e) {
  863. debugln(e);
  864. }
  865. return base;
  866. } unittest { mixin(S_TRACE);
  867. debug mixin(UTPerf);
  868. assert (createNewName("aaa", (string n) {return n != "aaa" && n != "aaa (2)";}, true) == "aaa (3)");
  869. assert (createNewName("aaa", (string n) {return n != "aaa" && n != "aaa(2)";}, false) == "aaa(3)");
  870. assert (createNewName("aaa (2)", (string n) {return n != "aaa (2)" && n != "aaa (3)";}, true) == "aaa (4)");
  871. assert (createNewName("aaa(2)", (string n) {return n != "aaa(2)" && n != "aaa(3)";}, false) == "aaa(4)");
  872. assert (createNewName("1-2", (string n) {return n != "1-2" && n != "1-3" && n != "1-4";}, false) == "1-5");
  873. }
  874. /// ditto
  875. string createNewFileName(string path, bool isdir) { mixin(S_TRACE);
  876. string parent = dirName(path);
  877. string name = baseName(path);
  878. string ext = isdir ? "" : .extension(name);
  879. if (!isdir) name = stripExtension(name);
  880. name = createNewName(name, (string name) { mixin(S_TRACE);
  881. name = std.path.buildPath(parent, name);
  882. if (!isdir && ext.length) name = setExtension(name, ext);
  883. return !.exists(name);
  884. }, false);
  885. name = std.path.buildPath(parent, name);
  886. if (!isdir && ext.length) name = setExtension(name, ext);
  887. return name;
  888. }
  889. /// ?????????????????????????????????
  890. @property
  891. string singleLine(string s) { mixin(S_TRACE);
  892. string[] r;
  893. foreach (line; s.splitLines()) { mixin(S_TRACE);
  894. r ~= line.strip();
  895. }
  896. return r.join();
  897. }
  898. /// ?????\n??????
  899. string encodeLf(string s) { mixin(S_TRACE);
  900. s = replace(s, "\\", "\\\\");
  901. s = replace(s, "\n", "\\n");
  902. return s;
  903. } unittest { mixin(S_TRACE);
  904. debug mixin(UTPerf);
  905. assert (encodeLf("\\\\\n\n\\") == "\\\\\\\\\\n\\n\\\\");
  906. }
  907. /// strs?\n????????????
  908. /// lastLf?true?????????????\n??????
  909. string encodeLf(in string[] strs, bool lastLf = true) { mixin(S_TRACE);
  910. string r;
  911. foreach (i, string s; strs) { mixin(S_TRACE);
  912. r ~= replace(s, "\\", "\\\\");
  913. if (lastLf || i < strs.length - 1) { mixin(S_TRACE);
  914. r ~= "\\n";
  915. }
  916. }
  917. return r;
  918. } unittest { mixin(S_TRACE);
  919. debug mixin(UTPerf);
  920. assert (encodeLf(decodeLf("t\\\\e\\\\st\\ntest\\\\n\\\\")) == "t\\\\e\\\\st\\ntest\\\\n\\\\\\n");
  921. assert (encodeLf(decodeLf("t\\\\e\\\\st\\ntest\\\\n\\\\"), false) == "t\\\\e\\\\st\\ntest\\\\n\\\\");
  922. }
  923. /// \n????????str????????
  924. string decodeLf2(string str) { mixin(S_TRACE);
  925. dstring buf;
  926. bool bs = false;
  927. foreach (dchar c; str) { mixin(S_TRACE);
  928. if (bs) { mixin(S_TRACE);
  929. if (c == 'n') { mixin(S_TRACE);
  930. buf ~= "\n"d;
  931. } else if (c == '\\') { mixin(S_TRACE);
  932. buf ~= "\\"d;
  933. } else { mixin(S_TRACE);
  934. buf ~= "\\"d ~ c;
  935. }
  936. bs = false;
  937. } else { mixin(S_TRACE);
  938. if (c == '\\') { mixin(S_TRACE);
  939. bs = true;
  940. } else { mixin(S_TRACE);
  941. buf ~= c;
  942. }
  943. }
  944. }
  945. if (bs) { mixin(S_TRACE);
  946. buf ~= "\\";
  947. }
  948. return toUTF8(buf);
  949. } unittest { mixin(S_TRACE);
  950. debug mixin(UTPerf);
  951. assert (decodeLf("t\\\\e\\st\\ntest\\\\n\\") == ["t\\e\\st", "test\\n\\"]);
  952. assert (decodeLf("t\\\\e\\st\\n\\\\ntest\\\\n\\\\n\\n") == ["t\\e\\st", "\\ntest\\n\\n"]);
  953. }
  954. /// \n????????str????????
  955. /// ???1??????????????????
  956. /// useEmpty?false????????????
  957. string[] decodeLf(string str, bool useEmpty = false) { mixin(S_TRACE);
  958. string[] r;
  959. if (useEmpty) { mixin(S_TRACE);
  960. int last = 0;
  961. foreach (i, s; splitLines!string(decodeLf2(str))) { mixin(S_TRACE);
  962. r ~= s;
  963. if (s.length > 0) last = i + 1;
  964. }
  965. r.length = last;
  966. } else { mixin(S_TRACE);
  967. foreach (s; splitLines!string(decodeLf2(str))) { mixin(S_TRACE);
  968. if (s.length > 0) { mixin(S_TRACE);
  969. r ~= s;
  970. }
  971. }
  972. }
  973. return r;
  974. } unittest { mixin(S_TRACE);
  975. debug mixin(UTPerf);
  976. assert (decodeLf("t\\\\e\\st\\ntest\\\\n\\") == ["t\\e\\st", "test\\n\\"]);
  977. assert (decodeLf("t\\\\e\\st\\n\\\\ntest\\\\n\\\\n\\n") == ["t\\e\\st", "\\ntest\\n\\n"]);
  978. }
  979. /// b?True/False??????????
  980. string fromBool(bool b) { mixin(S_TRACE);
  981. return b ? "True" : "False";
  982. }
  983. /// True/False??????bool???????
  984. bool parseBool(string b) { mixin(S_TRACE);
  985. switch (b) {
  986. case "True":
  987. return true;
  988. case "False":
  989. return false;
  990. default:
  991. throw new Exception("Not bool: " ~ b);
  992. }
  993. }
  994. /// ???????????
  995. void removeAll(Key, Value)(ref Value[Key] table) { mixin(S_TRACE);
  996. typeof(table) init;
  997. table = init;
  998. }
  999. /// T??????????true????
  1000. bool isSorted(T)(in T[] arr) { mixin(S_TRACE);
  1001. auto dlg = (in T a, in T b) {return a < b;};
  1002. return isSortedDlg!(T, typeof(dlg))(arr, dlg);
  1003. }
  1004. /// ditto
  1005. bool isSortedDlg(T, Dlg)(in T[] arr, Dlg cmp) { mixin(S_TRACE);
  1006. foreach (i, v; arr) { mixin(S_TRACE);
  1007. if (arr.length <= i + 1) break;
  1008. if (!cmp(v, arr[i + 1])) { mixin(S_TRACE);
  1009. return false;
  1010. }
  1011. }
  1012. return true;
  1013. } unittest { mixin(S_TRACE);
  1014. debug mixin(UTPerf);
  1015. assert (isSorted([1, 2, 3]));
  1016. assert (!isSorted([1, 3, 2]));
  1017. }
  1018. /// ????16?????????
  1019. /// Example:
  1020. /// ---
  1021. /// string result;
  1022. /// result = toHex("aBc");
  1023. /// assert (result == "%61%42%63", result);
  1024. /// result = toHex("???");
  1025. /// assert (result == "%E3%81%82%E3%81%84%E3%81%86", result);
  1026. /// ---
  1027. string toHex(string str) { mixin(S_TRACE);
  1028. string r;
  1029. foreach (i, c; str) { mixin(S_TRACE);
  1030. r ~= "%" ~ format("%02X", cast(int) c);
  1031. }
  1032. return r;
  1033. } unittest { mixin(S_TRACE);
  1034. debug mixin(UTPerf);
  1035. string result;
  1036. result = toHex("aBc");
  1037. assert (result == "%61%42%63", result);
  1038. result = toHex("???");
  1039. assert (result == "%E3%81%82%E3%81%84%E3%81%86", result);
  1040. }
  1041. private import std.c.stdlib;
  1042. private import std.c.string;
  1043. /// ????env??????????????null????
  1044. string getenv(string env) { mixin(S_TRACE);
  1045. auto v = std.c.stdlib.getenv((env ~ '\0').ptr);
  1046. if (!v) return null;
  1047. string r = v[0u .. strlen(v)].idup;
  1048. version (Windows) {
  1049. r = touni(r);
  1050. }
  1051. return r;
  1052. }
  1053. private string createFileImpl(bool Dir)(string parent, string name, string ext, string prefix) { mixin(S_TRACE);
  1054. string clean(string name) { mixin(S_TRACE);
  1055. name = replace(name, dirSeparator, "");
  1056. static if (altDirSeparator.length) {
  1057. name = replace(name, altDirSeparator, "");
  1058. }
  1059. name = replace(name, ".", "");
  1060. name = replace(name, " ", "");
  1061. if (name.length == 0) { mixin(S_TRACE);
  1062. name = "noname";
  1063. }
  1064. return name;
  1065. }
  1066. string r;
  1067. void create() { mixin(S_TRACE);
  1068. r = prefix ~ name;
  1069. r = r.toFileName();
  1070. if (ext.length) r = setExtension(r, ext);
  1071. r = std.path.buildPath(parent, r);
  1072. r = createNewFileName(r, Dir);
  1073. }
  1074. name = clean(name);
  1075. create();
  1076. return r;
  1077. }
  1078. /// ??????????????????
  1079. /// ?????????????????????"test(2).txt"????
  1080. /// ???????????
  1081. /// ??????????????????????????????
  1082. string createFileI(string parent, string name, string ext, string prefix) { mixin(S_TRACE);
  1083. return createFileImpl!(false)(parent, name, ext, prefix);
  1084. }
  1085. /// ditto
  1086. string createFolder(string parent, string name) { mixin(S_TRACE);
  1087. return createFileImpl!(true)(parent, name, "", "");
  1088. }
  1089. /// ?????????????
  1090. void preRemove(string delpath) { mixin(S_TRACE);
  1091. version (Windows) {
  1092. // ???????????
  1093. auto fname = std.utf.toUTFz!(wchar*)(delpath);
  1094. SetFileAttributesW(fname, FILE_ATTRIBUTE_NORMAL);
  1095. }
  1096. }
  1097. /// ?????????????????????????(2)?(3)?
  1098. /// ……?????????????????
  1099. /// Params:
  1100. /// sPath = ????????
  1101. /// path = ??????????
  1102. /// added = ????????????????????
  1103. /// binImgToRef = ?????????????????
  1104. /// Returns: ????????????
  1105. string copyTo(string sPath, string path, string added, bool binImgToRef) { mixin(S_TRACE);
  1106. bool binImg = isBinImg(path);
  1107. if (binImg && !binImgToRef) return path;
  1108. auto mtDir = std.path.buildPath(sPath, added);
  1109. if (!exists(mtDir)) mkdirRecurse(mtDir);
  1110. string to;
  1111. if (binImg) { mixin(S_TRACE);
  1112. to = std.path.buildPath(mtDir, "@simage(1).bmp");
  1113. } else { mixin(S_TRACE);
  1114. to = std.path.buildPath(mtDir, baseName(path));
  1115. }
  1116. to = createNewFileName(to, false);
  1117. if (binImg) { mixin(S_TRACE);
  1118. std.file.write(to, strToBImg(path));
  1119. } else { mixin(S_TRACE);
  1120. copy(path, to);
  1121. }
  1122. return std.path.buildPath(added, baseName(to));
  1123. }
  1124. /// a??b???????????????????????
  1125. void copyAll(string a, string b, bool overwrite = false) { mixin(S_TRACE);
  1126. if (isDir(a)) { mixin(S_TRACE);
  1127. if (!.exists(b)) mkdir(b);
  1128. foreach (file; clistdir(a)) { mixin(S_TRACE);
  1129. string fPath = std.path.buildPath(a, file);
  1130. string tPath = std.path.buildPath(b, file);
  1131. copyAll(fPath, tPath);
  1132. }
  1133. } else { mixin(S_TRACE);
  1134. if (overwrite && .exists(b)) delAll(b);
  1135. std.file.copy(a, b);
  1136. }
  1137. }
  1138. /// listDir????????????????????????????????
  1139. string[] clistdir(string dir) { mixin(S_TRACE);
  1140. string[] r;
  1141. if (!.exists(dir)) return r;
  1142. foreach (string file; dirEntries(dir, SpanMode.shallow, false)) { mixin(S_TRACE);
  1143. r ~= file.baseName();
  1144. }
  1145. return r;
  1146. }
  1147. /// delpath???????????????????????
  1148. /// Params:
  1149. /// force = true??????????????????????????
  1150. void delAll(string delpath, bool force = true) { mixin(S_TRACE);
  1151. if (!.exists(delpath)) return;
  1152. void __delAll(string delpath, ref Exception ee) { mixin(S_TRACE);
  1153. try { mixin(S_TRACE);
  1154. preRemove(delpath);
  1155. if (isDir(delpath)) { mixin(S_TRACE);
  1156. foreach (file; clistdir(delpath)) { mixin(S_TRACE);
  1157. __delAll(std.path.buildPath(delpath, file), ee);
  1158. }
  1159. rmdir(delpath);
  1160. } else { mixin(S_TRACE);
  1161. std.file.remove(delpath);
  1162. }
  1163. } catch (Exception e) {
  1164. if (!force) throw e;
  1165. if (!ee) ee = new FileException(e.msg);
  1166. }
  1167. }
  1168. Exception e = null;
  1169. __delAll(delpath, e);
  1170. if (force && e) throw e;
  1171. }
  1172. /// arr?a??????true????
  1173. bool contains(string pred = "a == b", T1, T2)(in T1[] arr, in T2 a) { mixin(S_TRACE);
  1174. foreach (b; arr) { mixin(S_TRACE);
  1175. if (mixin(pred)) return true;
  1176. }
  1177. return false;
  1178. }
  1179. static if (0 == filenameCharCmp('A', 'a')) {
  1180. /// ???????????
  1181. alias icmp fncmp;
  1182. } else { mixin(S_TRACE);
  1183. /// ???????????
  1184. alias cmp fncmp;
  1185. }
  1186. /// ???a?b??????
  1187. /// ????????????????????????????
  1188. /// ????????????????
  1189. /// Example:
  1190. /// ---
  1191. /// assert (ncmp("42", "2") > 0);
  1192. /// assert (ncmp("02", "2") < 0);
  1193. /// assert (ncmp("abc42", "abc4") > 0);
  1194. /// assert (ncmp("abc4a", "abc4b") < 0);
  1195. /// assert (ncmp("abc", "def") < 0);
  1196. /// ---
  1197. int ncmp(C1, C2)(in C1[] a, in C2[] b) { mixin(S_TRACE);
  1198. return ncmpImpl!(C1, C2, std.string.cmp)(a, b);
  1199. }
  1200. /// ditto
  1201. int incmp(C1, C2)(in C1[] a, in C2[] b) { mixin(S_TRACE);
  1202. return ncmpImpl!(C1, C2, std.string.icmp)(a, b);
  1203. } unittest {
  1204. assert (incmp("a1", "A2") < 0);
  1205. assert (incmp("A1", "a2") < 0);
  1206. }
  1207. /// ditto
  1208. int fnncmp(C1, C2)(in C1[] a, in C2[] b) { mixin(S_TRACE);
  1209. return ncmpImpl!(C1, C2, fncmp)(a, b);
  1210. }
  1211. private int ncmpImpl(C1, C2, alias Cmp)(in C1[] a0, in C2[] b0) { mixin(S_TRACE);
  1212. auto a = to!dstring(a0);
  1213. auto b = to!dstring(b0);
  1214. for (size_t i = 0, j = 0; i < a.length || j < b.length;) { mixin(S_TRACE);
  1215. if (i >= a.length) return -1;
  1216. if (j >= b.length) return 1;
  1217. C1[] buf1;
  1218. for (size_t k = i; k < a.length && std.ascii.isDigit(a[k]); k++) { mixin(S_TRACE);
  1219. buf1 ~= a[k];
  1220. }
  1221. C2[] buf2;
  1222. for (size_t k = j; k < b.length && std.ascii.isDigit(b[k]); k++) { mixin(S_TRACE);
  1223. buf2 ~= b[k];
  1224. }
  1225. if (buf1.length && buf2.length) { mixin(S_TRACE);
  1226. int cr;
  1227. if (buf1.length < buf2.length) { mixin(S_TRACE);
  1228. cr = Cmp(zfill_(buf1, buf2.length), buf2);
  1229. if (cr != 0) return cr;
  1230. } else if (buf1.length > buf2.length) { mixin(S_TRACE);
  1231. cr = Cmp(buf1, zfill_(buf2, buf1.length));
  1232. if (cr != 0) return cr;
  1233. }
  1234. cr = Cmp(buf1, buf2);
  1235. if (cr != 0) return cr;
  1236. i += buf1.length;
  1237. j += buf2.length;
  1238. } else { mixin(S_TRACE);
  1239. if (Cmp(a[i..i+1], b[j..j+1]) < 0) return -1;
  1240. if (Cmp(a[i..i+1], b[j..j+1]) > 0) return 1;
  1241. i++;
  1242. j++;
  1243. }
  1244. }
  1245. return 0;
  1246. } unittest { mixin(S_TRACE);
  1247. debug mixin(UTPerf);
  1248. assert (ncmp("42", "2") > 0);
  1249. assert (ncmp("02", "2") < 0);
  1250. assert (ncmp("abc42", "abc4") > 0);
  1251. assert (ncmp("abc4a", "abc4b") < 0);
  1252. assert (ncmp("abc", "def") < 0);
  1253. }
  1254. private C[] zfill_(C)(in C[] str, size_t width) { mixin(S_TRACE);
  1255. if (str.length >= width) return cast(C[]) str.dup;
  1256. Unqual!(C)[] r;
  1257. r.length = width;
  1258. size_t n = width - str.length;
  1259. r[0 .. n] = '0';
  1260. r[n .. $] = str;
  1261. return cast(C[]) r;
  1262. } unittest { mixin(S_TRACE);
  1263. debug mixin(UTPerf);
  1264. assert (zfill_("abc", 2) == "abc");
  1265. assert (zfill_("abc", 3) == "abc");
  1266. assert (zfill_("abc", 4) == "0abc");
  1267. assert (zfill_("abc", 5) == "00abc");
  1268. assert (zfill_("abc"w, 5) == "00abc"w);
  1269. assert (zfill_("abc"d, 5) == "00abc"d);
  1270. }
  1271. /// arr??a??????
  1272. T[] remove(string pred = "a == b", T)(ref T[] arr, T a) { mixin(S_TRACE);
  1273. foreach (i, b; arr) { mixin(S_TRACE);
  1274. if (mixin (pred)) { mixin(S_TRACE);
  1275. return (arr = arr[0 .. i] ~ arr[i + 1 .. $]);
  1276. }
  1277. }
  1278. return arr;
  1279. }
  1280. /// ???hashset?
  1281. class HashSet(T) {
  1282. private int[T] a;
  1283. /// ???????????
  1284. @property
  1285. this () { mixin(S_TRACE);
  1286. /// Nothing
  1287. }
  1288. /// ????????
  1289. void add(T v) { mixin(S_TRACE);
  1290. a[v] = 0;
  1291. }
  1292. /// ????????
  1293. void remove(T v) { mixin(S_TRACE);
  1294. a.remove(v);
  1295. }
  1296. /// ??????????
  1297. void clear() { mixin(S_TRACE);
  1298. int[T] init;
  1299. a = init;
  1300. }
  1301. /// ???????true?
  1302. const
  1303. bool contains(T v) { mixin(S_TRACE);
  1304. return (v in a) !is null;
  1305. }
  1306. /// ????
  1307. @property
  1308. const
  1309. size_t size() { mixin(S_TRACE);
  1310. return a.length;
  1311. }
  1312. /// ?????true?
  1313. @property
  1314. const
  1315. bool isEmpty() { mixin(S_TRACE);
  1316. return a.length == 0u;
  1317. }
  1318. int opApply(int delegate(ref T) dg) { mixin(S_TRACE);
  1319. int r = 0;
  1320. foreach (t, v; a) { mixin(S_TRACE);
  1321. r = dg(t);
  1322. if (r) break;
  1323. }
  1324. return r;
  1325. }
  1326. const
  1327. T[] toArray() { mixin(S_TRACE);
  1328. return a.keys;
  1329. }
  1330. }
  1331. version (Windows) {
  1332. private const STARTF_USESHOWWINDOW = 0x01;
  1333. private const CREATE_NEW_CONSOLE = 0x10;
  1334. /// ?????????????????true????
  1335. bool exec(string process, string workDir = "", bool console = true, bool wait = false) { mixin(S_TRACE);
  1336. STARTUPINFO setup;
  1337. setup.cb = setup.sizeof;
  1338. memset(&setup, 0, setup.sizeof);
  1339. PROCESS_INFORMATION info;
  1340. DWORD flag = 0;
  1341. if (!console) { mixin(S_TRACE);
  1342. setup.dwFlags = STARTF_USESHOWWINDOW;
  1343. setup.wShowWindow = SW_HIDE;
  1344. flag |= CREATE_NEW_CONSOLE;
  1345. }
  1346. int r;
  1347. wchar[] procTemp;
  1348. procTemp.length = process.length + 1;
  1349. procTemp[0 .. $] = toUTFz!(wchar*)(process)[0 .. procTemp.length];
  1350. r = CreateProcessW(null, procTemp.ptr, null, null, false, flag, null,
  1351. workDir.length ? toUTFz!(wchar*)(workDir) : null, &setup, &info);
  1352. if (r) { mixin(S_TRACE);
  1353. if (wait) { mixin(S_TRACE);
  1354. WaitForSingleObject(info.hProcess, INFINITE);
  1355. }
  1356. CloseHandle(info.hThread);
  1357. return true;
  1358. }
  1359. return false;
  1360. }
  1361. } else { mixin(S_TRACE);
  1362. private extern (C) {
  1363. intptr_t fork();
  1364. }
  1365. import std.c.stdlib;
  1366. import std.process;
  1367. /// ?????????????????true????
  1368. /// FIXME: ????????????
  1369. bool exec(string process, string workDir = "", bool console = true, bool wait = false) { mixin(S_TRACE);
  1370. auto pid = fork();
  1371. if (pid < 0) { mixin(S_TRACE);
  1372. return false;
  1373. } else if (pid > 0) { mixin(S_TRACE);
  1374. return true;
  1375. } else { mixin(S_TRACE);
  1376. assert (pid == 0);
  1377. if (workDir.length) chdir(workDir);
  1378. if (execv(process, null) == -1) { mixin(S_TRACE);
  1379. exit(-1);
  1380. }
  1381. return true;
  1382. }
  1383. }
  1384. }
  1385. /// path?sPath?????????????true????
  1386. bool hasPath(string sPath, string path) { mixin(S_TRACE);
  1387. path = nabs(path);
  1388. sPath = nabs(sPath);
  1389. return cwx.utils.fnstartsWith(path, sPath)
  1390. && (path.length == sPath.length || startsWith(path[sPath.length .. $], dirSeparator));
  1391. } unittest { mixin(S_TRACE);
  1392. debug mixin(UTPerf);
  1393. version (Windows) {
  1394. assert (hasPath(`c:\test\aaa`, `c:\test\aaa\bbb`));
  1395. assert (!hasPath(`c:\test\aaa`, `c:\test\aaaaaa`));
  1396. assert (hasPath(`c:\test\aaa`, `c:\test\aaa`));
  1397. }
  1398. }
  1399. /// ??????????????????????????????
  1400. /// ??????????????
  1401. template FileCache(T ...) {
  1402. struct Cache {
  1403. std.datetime.SysTime ftm;
  1404. static if (T.length == 1) {
  1405. T[0] value;
  1406. } else { mixin(S_TRACE);
  1407. T values;
  1408. }
  1409. }
  1410. static const CACHE_MAX = 1024;
  1411. static Cache[string] caches;
  1412. static string[] cachePaths;
  1413. void putCache(string path, T v) { mixin(S_TRACE);
  1414. if (!exists(path)) return;
  1415. path = nabs(path);
  1416. static if (0 == filenameCharCmp('A', 'a')) {
  1417. path = std.string.toLower(path);
  1418. }
  1419. if (cachePaths.length >= CACHE_MAX) { mixin(S_TRACE);
  1420. caches.remove(cachePaths[0u]);
  1421. cachePaths = cachePaths[1u .. $];
  1422. }
  1423. caches[path] = Cache(timeLastModified(path), v);
  1424. cachePaths ~= path;
  1425. }
  1426. Cache* cache(string path) { mixin(S_TRACE);
  1427. if (!exists(path)) return null;
  1428. path = nabs(path);
  1429. static if (0 == filenameCharCmp('A', 'a')) {
  1430. path = std.string.toLower(path);
  1431. }
  1432. auto cache = path in caches;
  1433. if (!cache) return null;
  1434. return cache.ftm == timeLastModified(path) ? cache : null;
  1435. }
  1436. }
  1437. /// ????????????????????????true????
  1438. bool hasParDir(string path) { mixin(S_TRACE);
  1439. path = buildNormalizedPath(path);
  1440. if (startsWith(path, pardir ~ dirSeparator)) return true;
  1441. if (.countUntil(path, dirSeparator ~ pardir ~ dirSeparator) != -1) return true;
  1442. return false;
  1443. }
  1444. /// s?sub???????????????
  1445. /// std.string.count()??????????????????
  1446. size_t icount(string s, string sub) { mixin(S_TRACE);
  1447. int c = 0;
  1448. while (true) { mixin(S_TRACE);
  1449. auto i = std.string.indexOf(s, sub, std.string.CaseSensitive.no);
  1450. if (i < 0) return c;
  1451. c++;
  1452. s = s[i + sub.length .. $];
  1453. }
  1454. } unittest { mixin(S_TRACE);
  1455. debug mixin(UTPerf);
  1456. assert (icount("test", "Es") == 1);
  1457. assert (icount("aaaaaaa", "AA") == 3);
  1458. }
  1459. /// s?????from?to???????????
  1460. /// std.string.replace()??????????????????
  1461. string ireplace(string s, string from, string to) { mixin(S_TRACE);
  1462. string r = "";
  1463. while (true) { mixin(S_TRACE);
  1464. auto i = std.string.indexOf(s, from, std.string.CaseSensitive.no);
  1465. if (i < 0) return r ~ s;
  1466. r ~= s[0 .. i] ~ to;
  1467. s = s[i + from.length .. $];
  1468. }
  1469. } unittest { mixin(S_TRACE);
  1470. debug mixin(UTPerf);
  1471. assert (ireplace("testte", "te", "tea") == "teasttea");
  1472. assert (ireplace("test", "Es", "TT") == "tTTt");
  1473. assert (ireplace("aaaaaaa", "AA", "BB") == "BBBBBBa");
  1474. }
  1475. /// ???Count??Sep?????????????????
  1476. string formatNum(N, size_t Count = 3, string Sep = ",")(N num) { mixin(S_TRACE);
  1477. string s = to!(string)(num);
  1478. string buf;
  1479. while (s.length > Count) { mixin(S_TRACE);
  1480. if (buf.length) buf = Sep ~ buf;
  1481. buf = s[$ - Count .. $] ~ buf;
  1482. s = s[0 .. $ - Count];
  1483. }
  1484. if (buf.length) buf = Sep ~ buf;
  1485. buf = s ~ buf;
  1486. return buf;
  1487. } unittest { mixin(S_TRACE);
  1488. debug mixin(UTPerf);
  1489. assert (formatNum(123) == "123");
  1490. assert (formatNum(123456) == "123,456");
  1491. assert (formatNum(1234567) == "1,234,567");
  1492. }
  1493. /// arr?????????
  1494. T1[T2] dupAssocArray(T1, T2)(in T1[T2] arr) { mixin(S_TRACE);
  1495. T1[T2] arr2;
  1496. foreach (key, val; arr) { mixin(S_TRACE);
  1497. arr2[key] = val;
  1498. }
  1499. return arr2;
  1500. }
  1501. /// text???????
  1502. /// ???????????2??????????????????
  1503. /// Example:
  1504. /// ---
  1505. /// assert (lengthJ("?") == 2);
  1506. /// assert (lengthJ("??") == 4);
  1507. /// assert (lengthJ("1?") == 3);
  1508. /// assert (lengthJ("1000") == 4);
  1509. /// assert (lengthJ("100?") == 5);
  1510. /// ---
  1511. size_t lengthJ(in char[] text) { mixin(S_TRACE);
  1512. size_t len = 0u;
  1513. foreach (dchar c; text) { mixin(S_TRACE);
  1514. char[] s;
  1515. std.utf.encode(s, c);
  1516. len += s.length > 1u ? 2u : 1u;
  1517. }
  1518. return len;
  1519. } unittest { mixin(S_TRACE);
  1520. debug mixin(UTPerf);
  1521. assert (lengthJ("?") == 2);
  1522. assert (lengthJ("??") == 4);
  1523. assert (lengthJ("1?") == 3);
  1524. assert (lengthJ("1000") == 4);
  1525. assert (lengthJ("100?") == 5);
  1526. }
  1527. /// ????????????????????
  1528. size_t lineCount(in string[] lines) { mixin(S_TRACE);
  1529. int from = -1;
  1530. int to = -1;
  1531. foreach (i, l; lines) { mixin(S_TRACE);
  1532. if (l.length) { mixin(S_TRACE);
  1533. if (from == -1) from = i;
  1534. to = i + 1;
  1535. }
  1536. }
  1537. return to - from;
  1538. } unittest { mixin(S_TRACE);
  1539. debug mixin(UTPerf);
  1540. assert (lineCount(splitLines!string("\na\nb\n\nc\n\n")) == 4);
  1541. }
  1542. /// std.algorithm.countUntil?const?????????????
  1543. sizediff_t cCountUntil(string pred = "a == b", R1, R2)(R1 arr, R2 b) { mixin(S_TRACE);
  1544. foreach (i, a; arr) { mixin(S_TRACE);
  1545. if (mixin(pred)) { mixin(S_TRACE);
  1546. return i;
  1547. }
  1548. }
  1549. return -1;
  1550. }
  1551. /// lengthJ()????????????????????
  1552. /// Example:
  1553. /// ---
  1554. /// assert (sliceJ("?????", 2, 10) == "????");
  1555. /// assert (sliceJ("???e?", 2, 9) == "??e?");
  1556. /// assert (sliceJ("?????", 2, 9) == "???");
  1557. /// assert (sliceJ("?????", 1, 9) == "???");
  1558. /// assert (sliceJ("?????", 0, 9) == "????");
  1559. /// assert (sliceJ("?????", 3, 4) == "");
  1560. /// assert (sliceJ("?????", 3, 5) == "");
  1561. /// assert (sliceJ("?????", 3, 6) == "?");
  1562. /// ---
  1563. /// See_Also: lengthJ()
  1564. string sliceJ(string text, size_t from, size_t to) { mixin(S_TRACE);
  1565. void te() { mixin(S_TRACE);
  1566. string msg = "text: " ~ text ~ ", from: " ~ .to!(string)(from) ~ ", to: " ~ .to!(string)(to);
  1567. throw new Exception(msg, __FILE__, __LINE__);
  1568. }
  1569. if (from > to) te();
  1570. size_t i = 0u, j = 0u;
  1571. size_t s = size_t.max, e;
  1572. bool ok = false;
  1573. size_t len;
  1574. foreach (dchar c; text) { mixin(S_TRACE);
  1575. if (s == size_t.max && from <= j) s = i;
  1576. char[] cbuf;
  1577. std.utf.encode(cbuf, c);
  1578. len = cbuf.length;
  1579. i += len;
  1580. j += len > 1 ? 2 : 1;
  1581. if (to <= j) { mixin(S_TRACE);
  1582. e = to < j ? i - len : i;
  1583. if (s == size_t.max) s = e;
  1584. ok = true;
  1585. break;
  1586. }
  1587. }
  1588. if (!ok) te();
  1589. return text[s .. e];
  1590. } unittest { mixin(S_TRACE);
  1591. debug mixin(UTPerf);
  1592. assert (sliceJ("?????", 2, 10) == "????");
  1593. assert (sliceJ("???e?", 2, 9) == "??e?");
  1594. assert (sliceJ("?????", 2, 9) == "???");
  1595. assert (sliceJ("?????", 1, 9) == "???");
  1596. assert (sliceJ("?????", 0, 9) == "????");
  1597. assert (sliceJ("?????", 3, 4) == "");
  1598. assert (sliceJ("?????", 3, 5) == "");
  1599. assert (sliceJ("?????", 3, 6) == "?");
  1600. assert (sliceJ("1????", 3, 7) == "??");
  1601. assert (sliceJ("1????", 3, 8) == "??");
  1602. assert (sliceJ("1????", 3, 9) == "???");
  1603. assert (sliceJ("1?u??", 3, 8) == "u??");
  1604. assert (sliceJ("?????", 3, 3) == "");
  1605. }
  1606. /// strip()???????????????????????????
  1607. string astrip(string s) { mixin(S_TRACE);
  1608. return s.astripl().astripr();
  1609. }
  1610. /// ditto
  1611. string astripl(string s) { mixin(S_TRACE);
  1612. foreach (i, c; s) { mixin(S_TRACE);
  1613. if (!std.ascii.isWhite(c)) { mixin(S_TRACE);
  1614. return s[i .. $];
  1615. }
  1616. }
  1617. return "";
  1618. }
  1619. /// ditto
  1620. string astripr(string s) { mixin(S_TRACE);
  1621. foreach_reverse (i, c; s) { mixin(S_TRACE);
  1622. if (!std.ascii.isWhite(c)) { mixin(S_TRACE);
  1623. return s[0 .. i + 1];
  1624. }
  1625. }
  1626. return "";
  1627. }
  1628. /// '[' ']'????????????????globMatch()??????????????
  1629. bool cglobMatch(string a, string b) { mixin(S_TRACE);
  1630. b = b.replace("\\", "\\\\");
  1631. return Wildcard(b, 0 == filenameCharCmp('A', 'a')).match(a);
  1632. } unittest { mixin(S_TRACE);
  1633. debug mixin(UTPerf);
  1634. assert (cfnmatch(r"C:\path", r"C:\path"));
  1635. assert (cfnmatch(r"C:\path", r"C:/path"));
  1636. }
  1637. /// ????????????
  1638. bool cfnmatch(in char[] a, in char[] b) { mixin(S_TRACE);
  1639. return 0 == filenameCmp(a, b);
  1640. }
  1641. /// Name???????????????true?
  1642. template isVariableName(string Name) {
  1643. immutable isVariableName = is(typeof({mixin("int " ~ Name ~ ";");}));
  1644. }
  1645. static assert (!isVariableName!("version"));
  1646. static assert (isVariableName!("version_"));
  1647. /// Name???????????????????'_'??????
  1648. template variableName(string Name) {
  1649. immutable variableName = isVariableName!Name ? Name : Name ~ "_";
  1650. }
  1651. static assert (variableName!("version") == "version_");
  1652. static assert (variableName!("versio") == "versio");
  1653. version (Windows) {
  1654. extern (Windows) {
  1655. private alias UINT function(WCHAR c) PathGetCharTypeW;
  1656. private immutable GCT_INVALID = 0x0;
  1657. private immutable GCT_LFNCHAR = 0x1;
  1658. private immutable GCT_SHORTCHAR = 0x2;
  1659. private immutable GCT_WILD = 0x4;
  1660. private immutable GCT_SEPARATOR = 0x8;
  1661. private __gshared void* _shlwapi = null;
  1662. private __gshared PathGetCharTypeW _PathGetCharType = null;
  1663. }
  1664. shared static ~this() { mixin(S_TRACE);
  1665. if (_shlwapi) dlclose(_shlwapi);
  1666. }
  1667. }
  1668. /// ???????????????
  1669. @property
  1670. bool isFileNameChar(dchar c) { mixin(S_TRACE);
  1671. version (Windows) {
  1672. static immutable DN = "\\/:*?\"<>|"d;
  1673. if (!_shlwapi) { mixin(S_TRACE);
  1674. _shlwapi = dlopen("shlwapi.dll");
  1675. }
  1676. if (!_shlwapi) { mixin(S_TRACE);
  1677. debugln("not found: shlwapi.dll");
  1678. return -1 == std.string.indexOf(DN, c);
  1679. }
  1680. if (!_PathGetCharType) { mixin(S_TRACE);
  1681. _PathGetCharType = cast(PathGetCharTypeW) dlsym(_shlwapi, "PathGetCharTypeW");
  1682. }
  1683. if (!_PathGetCharType) { mixin(S_TRACE);
  1684. debugln("not found: PathGetCharTypeW");
  1685. return -1 == std.string.indexOf(DN, c);
  1686. }
  1687. foreach (wchar wc; [c]) { mixin(S_TRACE);
  1688. auto r = _PathGetCharType(wc);
  1689. if (!(GCT_LFNCHAR & r) && !(GCT_SHORTCHAR & r)) { mixin(S_TRACE);
  1690. return false;
  1691. }
  1692. }
  1693. return true;
  1694. } else version (Posix) {
  1695. static immutable DN = "/"d;
  1696. return 0 != c && -1 == std.string.indexOf(DN, c);
  1697. } else static assert (0);
  1698. }
  1699. /// ???????????????????c??????
  1700. string toFileName(string name, dchar c = '_') { mixin(S_TRACE);
  1701. dchar[] buf;
  1702. foreach (dchar n; name) { mixin(S_TRACE);
  1703. buf ~= isFileNameChar(n) ? n : c;
  1704. }
  1705. version (Windows) {
  1706. // ???'.'????????????
  1707. if (buf.length && '.' == buf[$ - 1]) { mixin(S_TRACE);
  1708. buf[$ - 1] = c;
  1709. }
  1710. }
  1711. return to!string(buf);
  1712. }
  1713. /// ??????????????
  1714. string exeName(string args0) { mixin(S_TRACE);
  1715. version (Windows) {
  1716. char[MAX_PATH] pathBuf;
  1717. if (GetModuleFileNameA(null, pathBuf.ptr, pathBuf.length)) { mixin(S_TRACE);
  1718. return fromMBSz(pathBuf.idup.ptr);
  1719. } else { mixin(S_TRACE);
  1720. version (Console) {
  1721. cwriteln("GetModuleFileName failure!");
  1722. }
  1723. }
  1724. } else version (linux) {
  1725. char[1024] buf;
  1726. buf[] = '\0';
  1727. if (-1 != .readlink("/proc/self/exe", buf.ptr, buf.sizeof)) { mixin(S_TRACE);
  1728. cdebugln(buf);
  1729. return buf[0 .. .strlen(buf.ptr)].idup;
  1730. }
  1731. }
  1732. return args0;
  1733. }
  1734. version (Windows) {
  1735. private extern (Windows) {
  1736. struct PROCESS_MEMORY_COUNTERS {
  1737. DWORD cb;
  1738. DWORD PageFaultCount;
  1739. SIZE_T PeakWorkingSetSize;
  1740. SIZE_T WorkingSetSize;
  1741. SIZE_T QuotaPeakPagedPoolUsage;
  1742. SIZE_T QuotaPagedPoolUsage;
  1743. SIZE_T QuotaPeakNonPagedPoolUsage;
  1744. SIZE_T QuotaNonPagedPoolUsage;
  1745. SIZE_T PagefileUsage;
  1746. SIZE_T PeakPagefileUsage;
  1747. }
  1748. alias BOOL function(HANDLE Process, PROCESS_MEMORY_COUNTERS* ppsmemCounters, DWORD cb) GetProcessMemoryIn…

Large files files are truncated, but you can click here to view the full file