pathsplit.cpp 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149
  1. #include "pathsplit.h"
  2. #include <util/stream/output.h>
  3. #include <util/generic/yexception.h>
  4. template <class T>
  5. static inline size_t ToReserve(const T& t) {
  6. size_t ret = t.size() + 5;
  7. for (auto it = t.begin(); it != t.end(); ++it) {
  8. ret += it->size();
  9. }
  10. return ret;
  11. }
  12. void TPathSplitTraitsUnix::DoParseFirstPart(const TStringBuf part) {
  13. if (part == TStringBuf(".")) {
  14. push_back(TStringBuf("."));
  15. return;
  16. }
  17. if (IsAbsolutePath(part)) {
  18. IsAbsolute = true;
  19. }
  20. DoParsePart(part);
  21. }
  22. void TPathSplitTraitsUnix::DoParsePart(const TStringBuf part0) {
  23. DoAppendHint(part0.size() / 8);
  24. TStringBuf next(part0);
  25. TStringBuf part;
  26. while (TStringBuf(next).TrySplit('/', part, next)) {
  27. AppendComponent(part);
  28. }
  29. AppendComponent(next);
  30. }
  31. void TPathSplitTraitsWindows::DoParseFirstPart(const TStringBuf part0) {
  32. TStringBuf part(part0);
  33. if (part == TStringBuf(".")) {
  34. push_back(TStringBuf("."));
  35. return;
  36. }
  37. if (IsAbsolutePath(part)) {
  38. IsAbsolute = true;
  39. if (part.size() > 1 && part[1] == ':') {
  40. Drive = part.SubStr(0, 2);
  41. part = part.SubStr(2);
  42. }
  43. }
  44. DoParsePart(part);
  45. }
  46. void TPathSplitTraitsWindows::DoParsePart(const TStringBuf part0) {
  47. DoAppendHint(part0.size() / 8);
  48. size_t pos = 0;
  49. TStringBuf part(part0);
  50. while (pos < part.size()) {
  51. while (pos < part.size() && this->IsPathSep(part[pos])) {
  52. ++pos;
  53. }
  54. const char* begin = part.data() + pos;
  55. while (pos < part.size() && !this->IsPathSep(part[pos])) {
  56. ++pos;
  57. }
  58. AppendComponent(TStringBuf(begin, part.data() + pos));
  59. }
  60. }
  61. TString TPathSplitStore::DoReconstruct(const TStringBuf slash) const {
  62. TString r;
  63. r.reserve(ToReserve(*this));
  64. if (IsAbsolute) {
  65. r.AppendNoAlias(Drive);
  66. r.AppendNoAlias(slash);
  67. }
  68. for (auto i = begin(); i != end(); ++i) {
  69. if (i != begin()) {
  70. r.AppendNoAlias(slash);
  71. }
  72. r.AppendNoAlias(*i);
  73. }
  74. return r;
  75. }
  76. void TPathSplitStore::AppendComponent(const TStringBuf comp) {
  77. if (!comp || comp == TStringBuf(".")) {
  78. // ignore
  79. } else if (comp == TStringBuf("..") && !empty() && back() != TStringBuf("..")) {
  80. pop_back();
  81. } else {
  82. // push back first .. also
  83. push_back(comp);
  84. }
  85. }
  86. TStringBuf TPathSplitStore::Extension() const {
  87. return size() > 0 ? CutExtension(back()) : TStringBuf();
  88. }
  89. template <>
  90. void Out<TPathSplit>(IOutputStream& o, const TPathSplit& ps) {
  91. o << ps.Reconstruct();
  92. }
  93. TString JoinPaths(const TPathSplit& p1, const TPathSplit& p2) {
  94. if (p2.IsAbsolute) {
  95. ythrow yexception() << "can not join " << p1 << " and " << p2;
  96. }
  97. return TPathSplit(p1).AppendMany(p2.begin(), p2.end()).Reconstruct();
  98. }
  99. TStringBuf CutExtension(const TStringBuf fileName) {
  100. if (fileName.empty()) {
  101. return fileName;
  102. }
  103. TStringBuf name;
  104. TStringBuf extension;
  105. fileName.RSplit('.', name, extension);
  106. if (name.empty()) {
  107. // dot at a start or not found
  108. return name;
  109. } else {
  110. return extension;
  111. }
  112. }