pathsplit.cpp 3.2 KB

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