util.d 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130
  1. /*
  2. * pixiv_down - CLI-based downloading tool for https://www.pixiv.net.
  3. * Copyright (C) 2023, 2024 Mio
  4. *
  5. * This program is free software: you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation, version 3 of the License.
  8. *
  9. * This program is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License
  15. * along with this program. If not, see <https://www.gnu.org/licenses/>.
  16. */
  17. module app.util;
  18. ///
  19. /// Attempt to make *path* safe for different operating systems.
  20. ///
  21. /// This will replace anything that is not: a hyphen ('-'), a period ('.'),
  22. /// an underscore ('_'), or a "word character" (includes numbers). Any
  23. /// characters found will be replaced by a hyphen.
  24. ///
  25. /// Only tested on Linux and Android.
  26. ///
  27. /// Params:
  28. /// path = The input path to replace characters with.
  29. ///
  30. /// Returns: A new string with the replacements made.
  31. ///
  32. string makeSafe(string path)
  33. {
  34. import std.regex : regex, replaceAll;
  35. import std.string : chomp, replace, strip;
  36. enum kReplacement = "-";
  37. // 2.076 compat: reg must not be 'const'. Doesn't work with replaceAll.
  38. auto reg = regex(`[^-\w._]`);
  39. const noSpaces = strip(path).replace(" ", kReplacement);
  40. const almostSafe = replaceAll(noSpaces, reg, kReplacement);
  41. return chomp(almostSafe, "._-");
  42. }
  43. string[] split(string self, char delimiter, int limit) {
  44. import std.string : indexOf;
  45. string[] sections;
  46. ptrdiff_t pointer = 0;
  47. ptrdiff_t lastPointer = 0;
  48. while ((pointer = indexOf(self, delimiter, lastPointer)) != -1) {
  49. if (sections.length < limit - 1) {
  50. sections ~= self[lastPointer..pointer];
  51. lastPointer = pointer + 1;
  52. } else {
  53. sections ~= self[lastPointer..$];
  54. pointer = self.length;
  55. break;
  56. }
  57. }
  58. if (sections.length == 0) {
  59. return [self];
  60. }
  61. // Final section (mainly if limit == 2)
  62. if (sections.length < limit) {
  63. sections ~= self[lastPointer..$];
  64. }
  65. return sections;
  66. }
  67. ///
  68. unittest
  69. {
  70. import std.format;
  71. pragma(inline, true)
  72. void assertEquals(T)(T t1, T t2) {
  73. assert(t1 == t2, format("Values not equal.\n\tExpected: %s\n\t Actual: %s", t1, t2));
  74. }
  75. const noMatch = "no-matches";
  76. const parts = noMatch.split(' ', 2);
  77. assertEquals(1, parts.length);
  78. assertEquals(noMatch, parts[0]);
  79. const option = "--flag=value";
  80. const argAndValue = option.split('=', 2);
  81. assertEquals(2, argAndValue.length);
  82. assertEquals("--flag", argAndValue[0]);
  83. assertEquals("value", argAndValue[1]);
  84. const str = "zero-one-two-three-four-five";
  85. const numbers = str.split('-', 3);
  86. assertEquals(3, numbers.length);
  87. assertEquals("zero", numbers[0]);
  88. assertEquals("one", numbers[1]);
  89. assertEquals("two-three-four-five", numbers[2]);
  90. }
  91. /**
  92. * Suspend the current thread for a random value between *lowest* and
  93. * *largest*.
  94. *
  95. * Params:
  96. * lowest = The lowest value to use for the random sleep duration.
  97. * largest = The largest value to use for the random sleep duration.
  98. * print = Print a message to `stderr` with sleep duration.
  99. */
  100. void sleep(int lowest, int largest, bool print = true)
  101. {
  102. import core.thread : Thread;
  103. import core.time : seconds;
  104. import std.random : Random, uniform, unpredictableSeed;
  105. auto seed = Random(unpredictableSeed);
  106. const secs = uniform(lowest, largest + 1, seed);
  107. if (print) {
  108. import std.stdio : stderr;
  109. stderr.writefln("Sleeping for %d seconds...", secs);
  110. }
  111. Thread.sleep(secs.seconds);
  112. }